Component Catalog
Internal UI component inventory, preview rules, and V2 registry contract.
Overview
Yayaw includes an internal component catalog at:
/dashboard/content/components
The catalog supports a mixed inventory:
- local components from
src/components/ui/* - imported components stored in DB snapshots (non-executable)
Related docs:
- Sections Catalog for reusable section creation from component recipes
- Design Tokens for runtime token preview behavior
- Control Plane for automation safety expectations
- CMS Overview for the full content stack
CMS Role
The component catalog is the CMS rendering inventory. It documents and previews the low-level UI pieces that sections can use, including local components and imported source snapshots. Components are not authored content by themselves; they are the safe rendering primitives used by reusable sections and direct page references.
Keep component imports non-executable, compile them into validated recipes, and publish only entries that pass compile and smoke-render checks.
Goals:
- list UI components from
src/components/ui - list imported UI components from DB revisions
- preview compatible components with live props controls
- show source files used by each entry
- validate token-aware rendering with the current runtime design tokens
Scope and Conventions
Local source of truth remains explicit: src/components/ui/catalog/registry.ts.
Current scope:
- top-level files in
src/components/ui/*.tsx - key entries for
src/components/ui/kibo-ui/*/index.tsx - key entry for
src/components/ui/yayaw-table/index.ts - imported entries from DB (
ui_component_registry_items) merged into the same inventory
Conventions:
- one catalog entry per key component
- one key component per folder for nested component directories
- target entrypoint is
index.tsxfor nested folders (legacy exceptions are explicit in the registry) - imported entries are global-scope registry items with source snapshots only
- collision rule is deterministic:
imported > localfor the same slug/id
Preview Model
Preview behavior is recipe-driven and shared with runtime rendering:
src/lib/server/services/components/ui-component-recipe-compiler.tssrc/components/ui/catalog/ui-recipe-renderer-server.tsxsrc/components/ui/catalog/ui-recipe-renderer-client.tsx
Flow:
- Source snapshot is compiled to
UiComponentRecipeV1. - Catalog preview renders the recipe with generated controls from
propSchema,apiSchema, andharnessSchema. - Block runtime resolves published recipe revisions and uses the same renderer path.
Runtime-only preview policy:
- catalog preview always uses the internal recipe renderer
- no external docs iframe is embedded in the preview panel
- preview parity checks happen through variant tabs when multiple libraries expose the same component key
Publication gating:
compiled + smoke render OK=>published(auto-publication for imports/recompile)- otherwise =>
draft_blocked
Soft delete:
- imported components are removed from catalog with publication status
deleted - source snapshots remain in DB for audit/replay
AI SDK Integration
AI-driven compile fallback and classification now use Vercel AI SDK:
src/lib/server/services/components/ui-component-ai-client.tssrc/lib/server/services/components/ui-component-recipe-ai-fallback.tssrc/lib/server/services/components/ui-component-import-classifier.ts
Rules:
- all AI outputs are validated with strict
zodschemas - model usage follows a built-in resilient fallback chain; page/block builders can still request a preferred model from UI controls
- deterministic fallback is always available if AI is unavailable
- no AI failure blocks import or compile pipelines
Library and Category Classification
Imported components are classified with a hybrid strategy:
- cache by
sourceHash(reuse previous classification metadata) - deterministic heuristics (library + group)
- AI SDK enrichment (library/category refinement)
Metadata persisted on registry rows:
librarygroupclassificationSourceclassificationVersionclassificationModel(when AI is used)
Category policy:
- normalized to lowercase kebab-case
- new categories are accepted automatically after normalization
Library policy:
- controlled values:
shadcn-ui,kibo-ui,yayaw,ai-sdk,custom
AI Elements Vendored Components
AI Elements is vendored under a dedicated namespace:
src/components/ui/ai-elements/*- catalog local registry ids use
ai-elements-*to avoid collisions with core shadcn ids
Install/update script:
bun run components:install-ai-elements
Script behavior:
- resolves
@ai-elementsregistry index - installs each registry item into
src/components/ui/ai-elements - skips existing files by default (
--allto reinstall every item) - regenerates
src/components/ui/ai-elements/index.ts - regenerates deterministic composite preview overrides in
src/lib/server/services/components/ui-component-ai-elements-preview-overrides.generated.ts - continues on per-item failure and reports a summary
Catalog behavior:
- vendored AI Elements files are listed in
src/components/ui/catalog/registry.ts - they are tagged as library
ai-sdk - unknown AI Elements families compile to
compositerecipes by default to keep previews available - local
ai-elements-*composite recipes are enriched by deterministic overrides generated from source snapshots (components:generate-ai-elements-previews) - imported AI Elements items automatically use
ai-elements-*slug prefix when their base slug would collide with an existing local catalog id - when multiple libraries expose the same canonical component key, preview tabs let users switch variants and display whether their normalized sources are identical or different
- the dashboard loads only catalog summaries first; the selected variant's recipe and source are loaded on demand so opening the Components page does not compile or transfer every component preview
Unified Entries and Variant Tabs
The inventory is grouped by logical component key, not by raw registry id.
Rules:
- one inventory row per canonical component key
- each row can expose multiple library variants (tabs in preview)
- selecting a library filter keeps a row visible when it has at least one variant from that library
- selecting a category filter keeps a row visible when at least one variant matches that category
Canonical Key Grouping Rules
Canonical key resolution is defined in:
src/components/ui/catalog/catalog-identity.ts
Current normalization:
ai-elements-*ids are grouped under their stripped base key- all other ids keep their original value as canonical key
Library variant order is deterministic:
shadcn-uiai-sdkkibo-uiyayawcustom
Import Flows and Registry Sync
V2 supports component management from the catalog UI for users with components:manage.
Supported add flows:
- shadcn command input
- full registry alias sync import (defaults to
onlyNew=true) - source snapshot paste (
name,sourceFile,sourceSnapshot) - MCP source snapshot import through
yayaw_component_import
Registry sync action:
syncRegistryAliasComponents(registryAlias, { onlyNew: true })
Non-blocking policy for new library releases:
- registry discovery uses index payload candidates (
index.jsonandregistry.json) - items not yet vendored locally can still be imported through DB snapshot pipeline
- allowlist validation remains enforced for source domains
MCP component tools expose the same DB-backed catalog boundary:
yayaw_components_listandyayaw_component_getinspect component inventoryyayaw_component_importstores and compiles a source snapshotyayaw_component_recompilerecompiles a stored snapshotyayaw_component_publishpublishes a compiled smoke-renderable revisionyayaw_component_deletesoft-deletes an imported entry
These tools do not mutate repository-local source files in production. If an agent needs to add or modify first-party React component files, that is a code change and should happen through a branch and pull request.
Block Planner Usage Hints
The block AI planner consumes catalog usage hints when available:
- short example snippet from CLI/persisted context
- key registry dependencies
- docs/examples links
This metadata is read-only and passed in prompt payload to improve component and prop selection in generated block trees. It does not execute any DB source code.
CLI-First Context Enrichment
Imports now resolve context from the official shadcn CLI first, then apply deterministic fallbacks.
Implementation points:
src/lib/server/actions/components/component-registry-actions.tssrc/lib/server/services/components/ui-component-shadcn-cli-context.tssrc/lib/server/services/components/shadcn-cli-runner.tssrc/lib/server/services/components/ui-component-recipe-import-enrichment.tssrc/lib/server/services/components/ui-component-import-preview-evidence.ts
Behavior:
- CLI runner is local-first (
bunx shadcn) withnpx -y shadcn@latestfallback, timeout, retry, and structured logs - resolver aggregates:
shadcn viewpayload metadata/filesshadcn docs --jsonlinks for core shadcn componentsshadcn search+shadcn viewfor registry example blocks
- resolved context includes:
sourceTitle/sourceDescriptionexampleSnippetsregistryDependencies- docs links (
docs,examples) - interaction hint (
click-trigger,selection, or inline fallback)
- preview evidence priority is deterministic:
CLI -> payload -> web -> source snapshot - context is cached in import metadata by
sourceHash(contextVersion, links, snippets, dependencies), so repeated imports avoid repeated CLI calls - when CLI context is unavailable, import remains non-blocking and compile/publish gating behavior is unchanged
- no external source code is executed; only metadata and snapshots are parsed
Interaction-first policy:
- overlay-like previews should prefer explicit click triggers over always-open states
- composite AI blueprints are neutral by default (no AI/chat-specific microcopy unless source evidence explicitly requires it)
Design Token Behavior
The catalog preview does not rely only on baseline CSS.
It resolves effective runtime tokens for the current session (global + organization overrides) and applies scoped CSS variables to the preview surface. This lets dashboard users validate UI components against the same semantic token values used at runtime.
Validation
Registry consistency is validated by tests:
- unique entry ids
- source file existence
demoIdreferences resolved by the demo map
Runtime/catalog guards:
- no DB code execution (source snapshots are never evaluated)
- publication blocked when compile diagnostics or smoke render fails
Useful commands:
bun test src/components/ui/catalog/registry.test.ts
bun test src/lib/server/services/components/ui-component-recipe-compiler.test.ts
bun test src/lib/server/services/components/ui-component-catalog-query.test.ts
bun run components:generate-ai-elements-previewsEnvironment Variables
OPENAI_API_KEYOPENAI_COMPONENTS_AI_FALLBACK
These OpenAI variables are optional and only affect AI SDK enrichment for imported
components. Local AI Elements preview overrides are fully deterministic and do not
require OPENAI_API_KEY.
Contract Direction
- global product scope
- source snapshot storage for audit/replay
- no runtime execution of DB-stored code
Reference type:
UiComponentRegistryItemV1insrc/components/ui/catalog/types.ts
DB tables:
ui_component_registry_itemsui_component_recipe_revisionsui_component_publications