{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "schema-viewer",
  "title": "Schema Viewer",
  "description": "JSON Schema visualizer with tree view, type badges, and required indicators",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/blocks/devtools/schema-viewer/components/elements/schema-viewer.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { ChevronDown, ChevronRight } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface JsonSchema {\n  type?: string | string[];\n  title?: string;\n  description?: string;\n  properties?: Record<string, JsonSchema>;\n  items?: JsonSchema;\n  required?: string[];\n  enum?: unknown[];\n  default?: unknown;\n  example?: unknown;\n  examples?: unknown[];\n  format?: string;\n  minimum?: number;\n  maximum?: number;\n  minLength?: number;\n  maxLength?: number;\n  pattern?: string;\n  oneOf?: JsonSchema[];\n  anyOf?: JsonSchema[];\n  allOf?: JsonSchema[];\n  $ref?: string;\n}\n\ninterface SchemaViewerProps {\n  schema: JsonSchema;\n  showExamples?: boolean;\n  className?: string;\n}\n\ninterface SchemaNodeProps {\n  name?: string;\n  schema: JsonSchema;\n  required?: boolean;\n  depth: number;\n  showExamples: boolean;\n}\n\nfunction TypeBadge({ type, format }: { type: string; format?: string }) {\n  const colors: Record<string, string> = {\n    string: \"bg-green-100 text-green-700 dark:bg-green-950 dark:text-green-300\",\n    number: \"bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-300\",\n    integer: \"bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-300\",\n    boolean:\n      \"bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-300\",\n    object:\n      \"bg-purple-100 text-purple-700 dark:bg-purple-950 dark:text-purple-300\",\n    array:\n      \"bg-orange-100 text-orange-700 dark:bg-orange-950 dark:text-orange-300\",\n    null: \"bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300\",\n  };\n\n  return (\n    <span\n      className={cn(\n        \"px-1.5 py-0.5 rounded text-xs font-mono\",\n        colors[type] || colors.string,\n      )}\n    >\n      {type}\n      {format && <span className=\"opacity-70\">({format})</span>}\n    </span>\n  );\n}\n\nfunction SchemaNode({\n  name,\n  schema,\n  required,\n  depth,\n  showExamples,\n}: SchemaNodeProps) {\n  const [isExpanded, setIsExpanded] = React.useState(depth < 2);\n\n  const handleToggle = React.useCallback(() => {\n    setIsExpanded((prev) => !prev);\n  }, []);\n\n  const type = Array.isArray(schema.type)\n    ? schema.type.join(\" | \")\n    : schema.type || \"any\";\n  const hasChildren =\n    schema.properties ||\n    schema.items ||\n    schema.oneOf ||\n    schema.anyOf ||\n    schema.allOf;\n\n  const example = schema.example ?? schema.examples?.[0] ?? schema.default;\n\n  return (\n    <div\n      className={cn(\"text-sm\", depth > 0 && \"ml-4 border-l border-border pl-3\")}\n      role=\"treeitem\"\n      aria-expanded={hasChildren ? isExpanded : undefined}\n    >\n      <div className=\"flex items-start gap-2 py-1\">\n        {hasChildren && (\n          <button\n            type=\"button\"\n            onClick={handleToggle}\n            aria-label={isExpanded ? \"Collapse\" : \"Expand\"}\n            className=\"mt-0.5 text-muted-foreground hover:text-foreground\"\n          >\n            {isExpanded ? (\n              <ChevronDown className=\"w-4 h-4\" />\n            ) : (\n              <ChevronRight className=\"w-4 h-4\" />\n            )}\n          </button>\n        )}\n        {!hasChildren && <div className=\"w-4\" aria-hidden=\"true\" />}\n\n        <div className=\"flex-1 min-w-0\">\n          <div className=\"flex items-center gap-2 flex-wrap\">\n            {name && (\n              <span className=\"font-medium text-foreground\">\n                {name}\n                {required && <span className=\"text-red-500 ml-0.5\">*</span>}\n              </span>\n            )}\n            <TypeBadge type={type} format={schema.format} />\n            {schema.enum && (\n              <span className=\"text-xs text-muted-foreground\">\n                enum: {schema.enum.map((v) => JSON.stringify(v)).join(\" | \")}\n              </span>\n            )}\n          </div>\n\n          {schema.description && (\n            <p className=\"text-muted-foreground text-xs mt-0.5\">\n              {schema.description}\n            </p>\n          )}\n\n          {showExamples && example !== undefined && (\n            <div className=\"mt-1 text-xs\">\n              <span className=\"text-muted-foreground\">Example: </span>\n              <code className=\"font-mono text-foreground bg-muted px-1 rounded\">\n                {JSON.stringify(example)}\n              </code>\n            </div>\n          )}\n\n          {(schema.minimum !== undefined || schema.maximum !== undefined) && (\n            <div className=\"mt-1 text-xs text-muted-foreground\">\n              {schema.minimum !== undefined && (\n                <span>min: {schema.minimum} </span>\n              )}\n              {schema.maximum !== undefined && (\n                <span>max: {schema.maximum}</span>\n              )}\n            </div>\n          )}\n\n          {(schema.minLength !== undefined ||\n            schema.maxLength !== undefined) && (\n            <div className=\"mt-1 text-xs text-muted-foreground\">\n              {schema.minLength !== undefined && (\n                <span>minLength: {schema.minLength} </span>\n              )}\n              {schema.maxLength !== undefined && (\n                <span>maxLength: {schema.maxLength}</span>\n              )}\n            </div>\n          )}\n\n          {schema.pattern && (\n            <div className=\"mt-1 text-xs text-muted-foreground\">\n              pattern: <code className=\"font-mono\">{schema.pattern}</code>\n            </div>\n          )}\n        </div>\n      </div>\n\n      {isExpanded && hasChildren && (\n        <div className=\"mt-1\" role=\"group\">\n          {schema.properties &&\n            Object.entries(schema.properties).map(([key, propSchema]) => (\n              <SchemaNode\n                key={key}\n                name={key}\n                schema={propSchema}\n                required={schema.required?.includes(key)}\n                depth={depth + 1}\n                showExamples={showExamples}\n              />\n            ))}\n\n          {schema.items && (\n            <SchemaNode\n              name=\"[items]\"\n              schema={schema.items}\n              depth={depth + 1}\n              showExamples={showExamples}\n            />\n          )}\n\n          {schema.oneOf && (\n            <div className=\"ml-4 border-l border-border pl-3\">\n              <span className=\"text-xs text-muted-foreground font-medium\">\n                oneOf:\n              </span>\n              {schema.oneOf.map((s, i) => (\n                <SchemaNode\n                  key={i}\n                  schema={s}\n                  depth={depth + 1}\n                  showExamples={showExamples}\n                />\n              ))}\n            </div>\n          )}\n\n          {schema.anyOf && (\n            <div className=\"ml-4 border-l border-border pl-3\">\n              <span className=\"text-xs text-muted-foreground font-medium\">\n                anyOf:\n              </span>\n              {schema.anyOf.map((s, i) => (\n                <SchemaNode\n                  key={i}\n                  schema={s}\n                  depth={depth + 1}\n                  showExamples={showExamples}\n                />\n              ))}\n            </div>\n          )}\n\n          {schema.allOf && (\n            <div className=\"ml-4 border-l border-border pl-3\">\n              <span className=\"text-xs text-muted-foreground font-medium\">\n                allOf:\n              </span>\n              {schema.allOf.map((s, i) => (\n                <SchemaNode\n                  key={i}\n                  schema={s}\n                  depth={depth + 1}\n                  showExamples={showExamples}\n                />\n              ))}\n            </div>\n          )}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport function SchemaViewer({\n  schema,\n  showExamples = true,\n  className,\n}: SchemaViewerProps) {\n  return (\n    <div\n      data-slot=\"schema-viewer\"\n      role=\"tree\"\n      aria-label=\"JSON Schema\"\n      className={cn(\n        \"border border-border rounded-lg p-3 overflow-auto\",\n        className,\n      )}\n    >\n      {schema.title && (\n        <div className=\"mb-3 pb-2 border-b border-border\">\n          <h3 className=\"font-semibold text-foreground\">{schema.title}</h3>\n          {schema.description && (\n            <p className=\"text-sm text-muted-foreground mt-1\">\n              {schema.description}\n            </p>\n          )}\n        </div>\n      )}\n      <SchemaNode schema={schema} depth={0} showExamples={showExamples} />\n    </div>\n  );\n}\n\nexport type { SchemaViewerProps, JsonSchema };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Collapsible tree view, type badges, required indicators, constraints display, example values.",
  "categories": [
    "devtools"
  ],
  "type": "registry:ui"
}