{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "json-schema-editor",
	"type": "registry:ui",
	"title": "JSON Schema Editor",
	"description": "A visual editor for creating and editing JSON Schema definitions with support for nested objects, arrays, enums, and property descriptions.",
	"dependencies": ["nanoid"],
	"registryDependencies": ["button", "dialog", "input", "select"],
	"files": [
		{
			"path": "./src/registry/ui/json-schema-editor.tsx",
			"content": "\"use client\";\n\nimport type { JSONSchema7 } from \"ai\";\nimport { Asterisk, Brackets, Plus, Save, Trash2 } from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport { type ComponentProps, useState } from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTitle,\n\tDialogTrigger,\n} from \"@/components/ui/dialog\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n\tSelect,\n\tSelectContent,\n\tSelectItem,\n\tSelectTrigger,\n\tSelectValue,\n} from \"@/components/ui/select\";\nimport { cn } from \"@/lib/utils\";\n\nconst MAX_NESTING_LEVEL = 5;\n\nconst SCHEMA_TYPES = [\n\t\"string\",\n\t\"number\",\n\t\"integer\",\n\t\"boolean\",\n\t\"enum\",\n\t\"object\",\n] as const;\n\nexport type JsonSchemaEditorJSONSchemaType = (typeof SCHEMA_TYPES)[number];\n\nexport interface JsonSchemaEditorInternalSchemaProperty {\n\tid: string;\n\ttype: JsonSchemaEditorJSONSchemaType;\n\tisArray?: boolean;\n\tisRequired?: boolean;\n\tenumValues?: string[];\n\tproperties?: Record<string, JsonSchemaEditorInternalSchemaProperty>;\n\tdescription?: string;\n}\n\nexport interface JsonSchemaEditorInternalSchema {\n\ttype: \"object\";\n\tproperties: Record<string, JsonSchemaEditorInternalSchemaProperty>;\n\trequired?: string[];\n\tadditionalProperties?: boolean;\n\tdescription?: string;\n}\n\n/**\n * Parse a JSON Schema property into an internal representation\n * Shared utility for both editor and preview components\n */\nfunction parseJSONSchemaProperty(prop: Record<string, unknown>): {\n\ttype: string;\n\tisArray: boolean;\n\tdescription?: string;\n\tproperties?: Record<string, ReturnType<typeof parseJSONSchemaProperty>>;\n\tenumValues?: string[];\n} {\n\tconst result: {\n\t\ttype: string;\n\t\tisArray: boolean;\n\t\tdescription?: string;\n\t\tproperties?: Record<string, ReturnType<typeof parseJSONSchemaProperty>>;\n\t\tenumValues?: string[];\n\t} = {\n\t\ttype: \"string\",\n\t\tisArray: false,\n\t};\n\n\tif (prop.type === \"array\" && prop.items && typeof prop.items === \"object\") {\n\t\tresult.isArray = true;\n\t\tconst items = prop.items as Record<string, unknown>;\n\n\t\tif (typeof items.type === \"string\") {\n\t\t\tresult.type = items.type;\n\t\t}\n\n\t\tif (items.enum && Array.isArray(items.enum)) {\n\t\t\tresult.type = \"enum\";\n\t\t\tresult.enumValues = items.enum.map(String);\n\t\t}\n\n\t\tif (\n\t\t\titems.type === \"object\" &&\n\t\t\titems.properties &&\n\t\t\ttypeof items.properties === \"object\"\n\t\t) {\n\t\t\tresult.type = \"object\";\n\t\t\tresult.properties = {};\n\n\t\t\tfor (const [nestedName, nestedProp] of Object.entries(\n\t\t\t\titems.properties as Record<string, unknown>,\n\t\t\t)) {\n\t\t\t\tif (typeof nestedProp === \"object\" && nestedProp !== null) {\n\t\t\t\t\tresult.properties[nestedName] = parseJSONSchemaProperty(\n\t\t\t\t\t\tnestedProp as Record<string, unknown>,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif (typeof prop.type === \"string\") {\n\t\t\tresult.type = prop.type;\n\t\t}\n\n\t\tif (prop.enum && Array.isArray(prop.enum)) {\n\t\t\tresult.type = \"enum\";\n\t\t\tresult.enumValues = prop.enum.map(String);\n\t\t}\n\n\t\tif (\n\t\t\tprop.type === \"object\" &&\n\t\t\tprop.properties &&\n\t\t\ttypeof prop.properties === \"object\"\n\t\t) {\n\t\t\tresult.properties = {};\n\n\t\t\tfor (const [nestedName, nestedProp] of Object.entries(\n\t\t\t\tprop.properties as Record<string, unknown>,\n\t\t\t)) {\n\t\t\t\tif (typeof nestedProp === \"object\" && nestedProp !== null) {\n\t\t\t\t\tresult.properties[nestedName] = parseJSONSchemaProperty(\n\t\t\t\t\t\tnestedProp as Record<string, unknown>,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (prop.description && typeof prop.description === \"string\") {\n\t\tresult.description = prop.description;\n\t}\n\n\treturn result;\n}\n\nfunction convertToStandardJSONSchema(\n\tschema: JsonSchemaEditorInternalSchema,\n): JSONSchema7 {\n\tconst convertProperty = (\n\t\tprop: JsonSchemaEditorInternalSchemaProperty,\n\t): Record<string, unknown> => {\n\t\tconst converted: Record<string, unknown> = {};\n\n\t\tif (prop.isArray) {\n\t\t\tconverted.type = \"array\";\n\t\t\tconst itemType: Record<string, unknown> = { type: prop.type };\n\n\t\t\tif (prop.type === \"object\" && prop.properties) {\n\t\t\t\tconst nestedProperties: Record<string, unknown> = {};\n\t\t\t\tconst nestedRequired: string[] = [];\n\n\t\t\t\tfor (const [name, nestedProp] of Object.entries(\n\t\t\t\t\tprop.properties,\n\t\t\t\t)) {\n\t\t\t\t\tnestedProperties[name] = convertProperty(nestedProp);\n\t\t\t\t\tif (nestedProp.isRequired) {\n\t\t\t\t\t\tnestedRequired.push(name);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\titemType.properties = nestedProperties;\n\t\t\t\tif (nestedRequired.length > 0) {\n\t\t\t\t\titemType.required = nestedRequired;\n\t\t\t\t}\n\t\t\t} else if (prop.type === \"enum\" && prop.enumValues) {\n\t\t\t\titemType.enum = prop.enumValues;\n\t\t\t}\n\n\t\t\tconverted.items = itemType;\n\t\t} else {\n\t\t\tconverted.type = prop.type;\n\n\t\t\tif (prop.type === \"enum\" && prop.enumValues) {\n\t\t\t\tconverted.enum = prop.enumValues;\n\t\t\t\tdelete converted.type;\n\t\t\t}\n\n\t\t\tif (prop.type === \"object\" && prop.properties) {\n\t\t\t\tconst nestedProperties: Record<string, unknown> = {};\n\t\t\t\tconst nestedRequired: string[] = [];\n\n\t\t\t\tfor (const [name, nestedProp] of Object.entries(\n\t\t\t\t\tprop.properties,\n\t\t\t\t)) {\n\t\t\t\t\tnestedProperties[name] = convertProperty(nestedProp);\n\t\t\t\t\tif (nestedProp.isRequired) {\n\t\t\t\t\t\tnestedRequired.push(name);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconverted.properties = nestedProperties;\n\t\t\t\tif (nestedRequired.length > 0) {\n\t\t\t\t\tconverted.required = nestedRequired;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (prop.description) {\n\t\t\tconverted.description = prop.description;\n\t\t}\n\n\t\treturn converted;\n\t};\n\n\tconst result: Record<string, unknown> = {\n\t\ttype: \"object\",\n\t\tproperties: {},\n\t};\n\n\tconst properties: Record<string, unknown> = {};\n\tconst required: string[] = [];\n\n\tfor (const [name, prop] of Object.entries(schema.properties || {})) {\n\t\tproperties[name] = convertProperty(prop);\n\t\tif (prop.isRequired) {\n\t\t\trequired.push(name);\n\t\t}\n\t}\n\n\tresult.properties = properties;\n\tif (required.length > 0) {\n\t\tresult.required = required;\n\t}\n\n\tif (schema.description) {\n\t\tresult.description = schema.description;\n\t}\n\n\treturn result;\n}\n\nfunction convertFromStandardJSONSchema(\n\tschema: JSONSchema7 | null,\n): JsonSchemaEditorInternalSchema {\n\tif (!schema || typeof schema !== \"object\") {\n\t\treturn {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {},\n\t\t};\n\t}\n\n\tconst convertProperty = (\n\t\tprop: Record<string, unknown>,\n\t\tisRequired = false,\n\t): JsonSchemaEditorInternalSchemaProperty => {\n\t\tconst parsed = parseJSONSchemaProperty(prop);\n\n\t\tconst internal: JsonSchemaEditorInternalSchemaProperty = {\n\t\t\tid: nanoid(),\n\t\t\ttype: parsed.type as JsonSchemaEditorJSONSchemaType,\n\t\t\tisArray: parsed.isArray,\n\t\t\tisRequired,\n\t\t\tdescription: parsed.description,\n\t\t\tenumValues: parsed.enumValues,\n\t\t};\n\n\t\tif (parsed.properties) {\n\t\t\tinternal.properties = {};\n\t\t\tconst requiredArray = Array.isArray(prop.required)\n\t\t\t\t? prop.required\n\t\t\t\t: [];\n\n\t\t\tfor (const [name, nestedParsed] of Object.entries(\n\t\t\t\tparsed.properties,\n\t\t\t)) {\n\t\t\t\tinternal.properties[name] = convertProperty(\n\t\t\t\t\tnestedParsed as unknown as Record<string, unknown>,\n\t\t\t\t\trequiredArray.includes(name),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn internal;\n\t};\n\n\tconst result: JsonSchemaEditorInternalSchema = {\n\t\ttype: \"object\",\n\t\tproperties: {},\n\t};\n\n\tif (schema.properties && typeof schema.properties === \"object\") {\n\t\tconst requiredArray = Array.isArray(schema.required)\n\t\t\t? schema.required\n\t\t\t: [];\n\n\t\tfor (const [name, prop] of Object.entries(\n\t\t\tschema.properties as Record<string, unknown>,\n\t\t)) {\n\t\t\tif (typeof prop === \"object\" && prop !== null) {\n\t\t\t\tconst converted = convertProperty(\n\t\t\t\t\tprop as Record<string, unknown>,\n\t\t\t\t);\n\t\t\t\tconverted.isRequired = requiredArray.includes(name);\n\t\t\t\tresult.properties[name] = converted;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (schema.description && typeof schema.description === \"string\") {\n\t\tresult.description = schema.description;\n\t}\n\n\treturn result;\n}\n\n// ============================================================================\n// Schema Editor Components\n// ============================================================================\n\ninterface JsonSchemaEditorProps {\n\tinitialSchema: JSONSchema7;\n\tonSave: (schema: JSONSchema7) => void;\n\tonClose: () => void;\n\tclassName?: string;\n}\n\nexport function JsonSchemaEditor({\n\tinitialSchema,\n\tonSave,\n\tonClose,\n\tclassName,\n}: JsonSchemaEditorProps) {\n\tconst [internalSchema, setInternalSchema] =\n\t\tuseState<JsonSchemaEditorInternalSchema>(() =>\n\t\t\tconvertFromStandardJSONSchema(initialSchema),\n\t\t);\n\n\tconst [schemaDescription, setSchemaDescription] = useState<string>(\n\t\tinitialSchema?.description || \"\",\n\t);\n\n\tconst handleInternalChange = (updated: JsonSchemaEditorInternalSchema) => {\n\t\tsetInternalSchema(updated);\n\t};\n\n\tconst handleSave = () => {\n\t\tconst standardSchema = convertToStandardJSONSchema(internalSchema);\n\t\tif (schemaDescription.trim()) {\n\t\t\tstandardSchema.description = schemaDescription.trim();\n\t\t}\n\t\tonSave(standardSchema);\n\t\tonClose();\n\t};\n\n\tconst handleReset = () => {\n\t\tsetInternalSchema({\n\t\t\ttype: \"object\",\n\t\t\tproperties: {},\n\t\t});\n\t};\n\n\tconst handleAddProperty = () => {\n\t\tconst existingKeys = Object.keys(internalSchema.properties || {});\n\t\tlet counter = 1;\n\t\tlet newName = `property-${counter}`;\n\t\twhile (existingKeys.includes(newName)) {\n\t\t\tcounter++;\n\t\t\tnewName = `property-${counter}`;\n\t\t}\n\n\t\tconst newProperty: JsonSchemaEditorInternalSchemaProperty = {\n\t\t\tid: nanoid(),\n\t\t\ttype: \"string\",\n\t\t\tisArray: false,\n\t\t\tisRequired: false,\n\t\t};\n\n\t\thandleInternalChange({\n\t\t\t...internalSchema,\n\t\t\tproperties: {\n\t\t\t\t...internalSchema.properties,\n\t\t\t\t[newName]: newProperty,\n\t\t\t},\n\t\t});\n\t};\n\n\tconst handleUpdateProperty = (\n\t\tname: string,\n\t\tproperty: JsonSchemaEditorInternalSchemaProperty,\n\t) => {\n\t\thandleInternalChange({\n\t\t\t...internalSchema,\n\t\t\tproperties: {\n\t\t\t\t...internalSchema.properties,\n\t\t\t\t[name]: property,\n\t\t\t},\n\t\t});\n\t};\n\n\tconst handleRenameProperty = (oldName: string, newName: string) => {\n\t\tif (oldName === newName) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newProperties: Record<\n\t\t\tstring,\n\t\t\tJsonSchemaEditorInternalSchemaProperty\n\t\t> = {};\n\t\tfor (const [key, value] of Object.entries(internalSchema.properties)) {\n\t\t\tif (key === oldName) {\n\t\t\t\tnewProperties[newName] = value;\n\t\t\t} else {\n\t\t\t\tnewProperties[key] = value;\n\t\t\t}\n\t\t}\n\n\t\thandleInternalChange({\n\t\t\t...internalSchema,\n\t\t\tproperties: newProperties,\n\t\t});\n\t};\n\n\tconst handleDeleteProperty = (name: string) => {\n\t\tconst newProperties = { ...internalSchema.properties };\n\t\tdelete newProperties[name];\n\n\t\thandleInternalChange({\n\t\t\t...internalSchema,\n\t\t\tproperties: newProperties,\n\t\t});\n\t};\n\n\treturn (\n\t\t<div className={cn(\"flex flex-col h-full gap-4\", className)}>\n\t\t\t<DialogHeader className=\"flex flex-row justify-start gap-4\">\n\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t<DialogTitle>Schema Editor</DialogTitle>\n\t\t\t\t\t<DialogDescription>\n\t\t\t\t\t\tEdit the schema for the agent output\n\t\t\t\t\t</DialogDescription>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<Button onClick={handleReset} variant=\"outline\" size=\"sm\">\n\t\t\t\t\t\tReset\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button onClick={handleSave} size=\"sm\">\n\t\t\t\t\t\t<Save size={16} className=\"mr-1\" />\n\t\t\t\t\t\tSave\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</DialogHeader>\n\t\t\t<div className=\"space-y-4\">\n\t\t\t\t<label\n\t\t\t\t\thtmlFor=\"schema-description\"\n\t\t\t\t\tclassName=\"text-sm font-medium\"\n\t\t\t\t>\n\t\t\t\t\tSchema Description\n\t\t\t\t</label>\n\t\t\t\t<Input\n\t\t\t\t\tid=\"schema-description\"\n\t\t\t\t\tvalue={schemaDescription}\n\t\t\t\t\tonChange={(e) => setSchemaDescription(e.target.value)}\n\t\t\t\t\tplaceholder=\"Overall schema description (optional)\"\n\t\t\t\t\tclassName=\"w-full\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div className=\"flex-1 flex flex-col overflow-y-auto\">\n\t\t\t\t{Object.entries(internalSchema.properties || {}).map(\n\t\t\t\t\t([name, property]) => (\n\t\t\t\t\t\t<JsonSchemaEditorPropertyRow\n\t\t\t\t\t\t\tkey={property.id}\n\t\t\t\t\t\t\tname={name}\n\t\t\t\t\t\t\tproperty={property}\n\t\t\t\t\t\t\tonUpdate={(updated) =>\n\t\t\t\t\t\t\t\thandleUpdateProperty(name, updated)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tonRename={(newName) =>\n\t\t\t\t\t\t\t\thandleRenameProperty(name, newName)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tonDelete={() => handleDeleteProperty(name)}\n\t\t\t\t\t\t\tonAddProperty={handleAddProperty}\n\t\t\t\t\t\t\tlevel={0}\n\t\t\t\t\t\t/>\n\t\t\t\t\t),\n\t\t\t\t)}\n\n\t\t\t\t<Button\n\t\t\t\t\tonClick={handleAddProperty}\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tclassName=\"w-full justify-start mt-2\"\n\t\t\t\t>\n\t\t\t\t\t<Plus size={16} />\n\t\t\t\t\tAdd Property\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\ninterface JsonSchemaEditorPropertyRowProps {\n\tname: string;\n\tproperty: JsonSchemaEditorInternalSchemaProperty;\n\tonUpdate: (property: JsonSchemaEditorInternalSchemaProperty) => void;\n\tonRename: (newName: string) => void;\n\tonDelete: () => void;\n\tonAddProperty: (parentPath?: string) => void;\n\tlevel: number;\n}\n\nfunction JsonSchemaEditorPropertyRow({\n\tname,\n\tproperty,\n\tonUpdate,\n\tonRename,\n\tonDelete,\n\tonAddProperty,\n\tlevel,\n}: JsonSchemaEditorPropertyRowProps) {\n\tconst isNested = property.type === \"object\";\n\tconst canNest = level < MAX_NESTING_LEVEL;\n\n\tconst handleAddNestedProperty = () => {\n\t\tif (!isNested) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst existingKeys = Object.keys(property.properties || {});\n\t\tlet counter = 1;\n\t\tlet newName = `property-${counter}`;\n\t\twhile (existingKeys.includes(newName)) {\n\t\t\tcounter++;\n\t\t\tnewName = `property-${counter}`;\n\t\t}\n\n\t\tconst newProperty: JsonSchemaEditorInternalSchemaProperty = {\n\t\t\tid: nanoid(),\n\t\t\ttype: \"string\",\n\t\t\tisArray: false,\n\t\t\tisRequired: false,\n\t\t};\n\n\t\tonUpdate({\n\t\t\t...property,\n\t\t\tproperties: {\n\t\t\t\t...(property.properties || {}),\n\t\t\t\t[newName]: newProperty,\n\t\t\t},\n\t\t});\n\t};\n\n\tconst handleDeleteNestedProperty = (propName: string) => {\n\t\tif (!isNested || !property.properties) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newProperties = { ...property.properties };\n\t\tdelete newProperties[propName];\n\n\t\tonUpdate({\n\t\t\t...property,\n\t\t\tproperties: newProperties,\n\t\t});\n\t};\n\n\tconst handleUpdateNestedProperty = (\n\t\tpropName: string,\n\t\tupdatedProperty: JsonSchemaEditorInternalSchemaProperty,\n\t) => {\n\t\tif (!isNested) {\n\t\t\treturn;\n\t\t}\n\n\t\tonUpdate({\n\t\t\t...property,\n\t\t\tproperties: {\n\t\t\t\t...(property.properties || {}),\n\t\t\t\t[propName]: updatedProperty,\n\t\t\t},\n\t\t});\n\t};\n\n\tconst handleRenameNestedProperty = (oldName: string, newName: string) => {\n\t\tif (!isNested || !property.properties || oldName === newName) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newProperties: Record<\n\t\t\tstring,\n\t\t\tJsonSchemaEditorInternalSchemaProperty\n\t\t> = {};\n\t\tfor (const [key, value] of Object.entries(property.properties)) {\n\t\t\tif (key === oldName) {\n\t\t\t\tnewProperties[newName] = value;\n\t\t\t} else {\n\t\t\t\tnewProperties[key] = value;\n\t\t\t}\n\t\t}\n\n\t\tonUpdate({\n\t\t\t...property,\n\t\t\tproperties: newProperties,\n\t\t});\n\t};\n\n\treturn (\n\t\t<div className=\"relative\">\n\t\t\t{level > 0 && (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"absolute top-0 bottom-0 w-0.5 bg-border\"\n\t\t\t\t\tstyle={{ left: `${(level - 1) * 20 + 20}px` }}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t<div\n\t\t\t\tclassName=\"flex items-center gap-2 py-2 px-3 hover:bg-muted/50 rounded-sm transition-colors w-full\"\n\t\t\t\tstyle={{ paddingLeft: `${level * 20 + 12}px` }}\n\t\t\t>\n\t\t\t\t<Input\n\t\t\t\t\tvalue={name}\n\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\tonRename(e.target.value);\n\t\t\t\t\t}}\n\t\t\t\t\tclassName=\"flex-1 min-w-0 h-8\"\n\t\t\t\t\tplaceholder=\"property-name\"\n\t\t\t\t/>\n\n\t\t\t\t<Input\n\t\t\t\t\tvalue={property.description || \"\"}\n\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\tonUpdate({\n\t\t\t\t\t\t\t...property,\n\t\t\t\t\t\t\tdescription: e.target.value,\n\t\t\t\t\t\t});\n\t\t\t\t\t}}\n\t\t\t\t\tclassName=\"flex-1 min-w-0 h-8 text-xs\"\n\t\t\t\t\tplaceholder=\"Description (optional)\"\n\t\t\t\t/>\n\n\t\t\t\t<Select\n\t\t\t\t\tvalue={property.type}\n\t\t\t\t\tonValueChange={(newType) => {\n\t\t\t\t\t\tconst updated: JsonSchemaEditorInternalSchemaProperty =\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...property,\n\t\t\t\t\t\t\t\ttype: newType as JsonSchemaEditorJSONSchemaType,\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (newType === \"object\" && !property.properties) {\n\t\t\t\t\t\t\tupdated.properties = {};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (newType !== \"enum\") {\n\t\t\t\t\t\t\tupdated.enumValues = undefined;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tonUpdate(updated);\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<SelectTrigger size=\"sm\" className=\"w-28 shrink-0\">\n\t\t\t\t\t\t<SelectValue placeholder=\"Type\" />\n\t\t\t\t\t</SelectTrigger>\n\t\t\t\t\t<SelectContent>\n\t\t\t\t\t\t{SCHEMA_TYPES.map((type) => (\n\t\t\t\t\t\t\t<SelectItem key={type} value={type}>\n\t\t\t\t\t\t\t\t{type}\n\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</SelectContent>\n\t\t\t\t</Select>\n\n\t\t\t\t<Button\n\t\t\t\t\tvariant={property.isArray ? \"default\" : \"outline\"}\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\tonUpdate({\n\t\t\t\t\t\t\t...property,\n\t\t\t\t\t\t\tisArray: !property.isArray,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Brackets size={16} />\n\t\t\t\t</Button>\n\n\t\t\t\t<Button\n\t\t\t\t\tvariant={property.isRequired ? \"default\" : \"outline\"}\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\tonUpdate({\n\t\t\t\t\t\t\t...property,\n\t\t\t\t\t\t\tisRequired: !property.isRequired,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Asterisk size={16} />\n\t\t\t\t</Button>\n\n\t\t\t\t<Button variant=\"destructive\" size=\"sm\" onClick={onDelete}>\n\t\t\t\t\t<Trash2 size={16} />\n\t\t\t\t</Button>\n\t\t\t</div>\n\n\t\t\t{property.type === \"enum\" && (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"py-2\"\n\t\t\t\t\tstyle={{ paddingLeft: `${level * 20 + 12}px` }}\n\t\t\t\t>\n\t\t\t\t\t<div className=\"text-xs font-medium mb-2 text-muted-foreground\">\n\t\t\t\t\t\tEnum Values:\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"space-y-1 mb-2 ml-4\">\n\t\t\t\t\t\t{(property.enumValues || []).map((value, index) => (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={`enum-${value}`}\n\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-2\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\t\t\tconst newEnumValues = [\n\t\t\t\t\t\t\t\t\t\t\t...(property.enumValues || []),\n\t\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t\t\tnewEnumValues[index] = e.target.value;\n\t\t\t\t\t\t\t\t\t\tonUpdate({\n\t\t\t\t\t\t\t\t\t\t\t...property,\n\t\t\t\t\t\t\t\t\t\t\tenumValues: newEnumValues,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tclassName=\"flex-1 h-8\"\n\t\t\t\t\t\t\t\t\tplaceholder=\"Enum value\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\tvariant=\"destructive\"\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tonUpdate({\n\t\t\t\t\t\t\t\t\t\t\t...property,\n\t\t\t\t\t\t\t\t\t\t\tenumValues: (\n\t\t\t\t\t\t\t\t\t\t\t\tproperty.enumValues || []\n\t\t\t\t\t\t\t\t\t\t\t).filter((_, i) => i !== index),\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Trash2 size={16} />\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"flex gap-2 ml-4\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tonUpdate({\n\t\t\t\t\t\t\t\t\t...property,\n\t\t\t\t\t\t\t\t\tenumValues: [\n\t\t\t\t\t\t\t\t\t\t...(property.enumValues || []),\n\t\t\t\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tclassName=\"h-7 px-2 text-xs\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Plus size={12} className=\"mr-1\" />\n\t\t\t\t\t\t\tAdd Value\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{isNested && canNest && (\n\t\t\t\t<div>\n\t\t\t\t\t{Object.entries(property.properties || {}).map(\n\t\t\t\t\t\t([propName, prop]) => (\n\t\t\t\t\t\t\t<JsonSchemaEditorPropertyRow\n\t\t\t\t\t\t\t\tkey={prop.id}\n\t\t\t\t\t\t\t\tname={propName}\n\t\t\t\t\t\t\t\tproperty={prop}\n\t\t\t\t\t\t\t\tonUpdate={(updated) =>\n\t\t\t\t\t\t\t\t\thandleUpdateNestedProperty(\n\t\t\t\t\t\t\t\t\t\tpropName,\n\t\t\t\t\t\t\t\t\t\tupdated,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tonRename={(newName) =>\n\t\t\t\t\t\t\t\t\thandleRenameNestedProperty(\n\t\t\t\t\t\t\t\t\t\tpropName,\n\t\t\t\t\t\t\t\t\t\tnewName,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tonDelete={() =>\n\t\t\t\t\t\t\t\t\thandleDeleteNestedProperty(propName)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tonAddProperty={onAddProperty}\n\t\t\t\t\t\t\t\tlevel={level + 1}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t),\n\t\t\t\t\t)}\n\n\t\t\t\t\t<Button\n\t\t\t\t\t\tonClick={handleAddNestedProperty}\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\tclassName=\"w-full justify-start\"\n\t\t\t\t\t\tstyle={{ paddingLeft: `${(level + 1) * 20 + 16}px` }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Plus size={16} />\n\t\t\t\t\t\tAdd Property\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\ninterface JsonSchemaEditorDialogProps {\n\tschema: JSONSchema7 | null;\n\tonSave: (schema: JSONSchema7) => void;\n}\n\nexport function JsonSchemaEditorDialog({\n\tschema,\n\tonSave,\n}: JsonSchemaEditorDialogProps) {\n\tconst [dialogOpen, setDialogOpen] = useState(false);\n\n\treturn (\n\t\t<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>\n\t\t\t<DialogTrigger asChild>\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" className=\"w-full\">\n\t\t\t\t\t{schema ? \"Edit Schema\" : \"Create Schema\"}\n\t\t\t\t</Button>\n\t\t\t</DialogTrigger>\n\t\t\t<DialogContent className=\"sm:max-w-4xl h-full sm:max-h-[90vh] flex flex-col overflow-hidden\">\n\t\t\t\t<JsonSchemaEditor\n\t\t\t\t\tinitialSchema={schema || { type: \"object\", properties: {} }}\n\t\t\t\t\tonSave={onSave}\n\t\t\t\t\tonClose={() => setDialogOpen(false)}\n\t\t\t\t/>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n\n// ============================================================================\n// Schema Preview\n// ============================================================================\n\nfunction parseJSONSchema(\n\tschema: JSONSchema7,\n): Record<string, ReturnType<typeof parseJSONSchemaProperty>> {\n\tif (!schema || typeof schema !== \"object\" || !schema.properties) {\n\t\treturn {};\n\t}\n\n\tconst properties: Record<\n\t\tstring,\n\t\tReturnType<typeof parseJSONSchemaProperty>\n\t> = {};\n\tfor (const [name, prop] of Object.entries(\n\t\tschema.properties as Record<string, unknown>,\n\t)) {\n\t\tif (typeof prop === \"object\" && prop !== null) {\n\t\t\tproperties[name] = parseJSONSchemaProperty(\n\t\t\t\tprop as Record<string, unknown>,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn properties;\n}\n\nfunction parseSchemaToPreview(\n\tschema: JSONSchema7,\n): JsonSchemaPreviewProperty[] {\n\tconst parsedProperties = parseJSONSchema(schema);\n\tconst required = Array.isArray(schema.required) ? schema.required : [];\n\n\tconst convertToSchemaProperty = (\n\t\tname: string,\n\t\tparsed: ReturnType<typeof parseJSONSchemaProperty>,\n\t\tisRequired: boolean,\n\t): JsonSchemaPreviewProperty => {\n\t\tconst result: JsonSchemaPreviewProperty = {\n\t\t\tname,\n\t\t\ttype: parsed.type,\n\t\t\tisArray: parsed.isArray,\n\t\t\tisRequired,\n\t\t\tdescription: parsed.description,\n\t\t\tproperties: undefined,\n\t\t\tenumValues: parsed.enumValues,\n\t\t};\n\n\t\tif (parsed.properties) {\n\t\t\tresult.properties = [];\n\t\t\tfor (const [nestedName, nestedParsed] of Object.entries(\n\t\t\t\tparsed.properties,\n\t\t\t)) {\n\t\t\t\tresult.properties.push(\n\t\t\t\t\tconvertToSchemaProperty(nestedName, nestedParsed, false),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t};\n\n\tconst properties: JsonSchemaPreviewProperty[] = [];\n\tfor (const [name, parsed] of Object.entries(parsedProperties)) {\n\t\tproperties.push(\n\t\t\tconvertToSchemaProperty(name, parsed, required.includes(name)),\n\t\t);\n\t}\n\n\treturn properties;\n}\n\ninterface JsonSchemaPreviewProps extends ComponentProps<\"div\"> {\n\tschema: JSONSchema7;\n}\n\nexport function JsonSchemaPreview({\n\tschema,\n\tclassName,\n\t...props\n}: JsonSchemaPreviewProps) {\n\tconst properties = parseSchemaToPreview(schema);\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"border rounded-md overflow-hidden\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"p-2 border-b bg-muted/50\">\n\t\t\t\t<h4 className=\"text-xs font-semibold\">Schema Structure</h4>\n\t\t\t</div>\n\t\t\t<div className=\"max-h-[200px] overflow-y-auto p-1\">\n\t\t\t\t{properties.length === 0 ? (\n\t\t\t\t\t<div className=\"p-4 text-xs text-muted-foreground text-center\">\n\t\t\t\t\t\tNo properties defined\n\t\t\t\t\t</div>\n\t\t\t\t) : (\n\t\t\t\t\tproperties.map((property) => (\n\t\t\t\t\t\t<JsonSchemaPreviewPropertyRow\n\t\t\t\t\t\t\tkey={property.name}\n\t\t\t\t\t\t\tproperty={property}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\ninterface JsonSchemaPreviewProperty {\n\tname: string;\n\ttype: string;\n\tisArray: boolean;\n\tisRequired: boolean;\n\tdescription?: string;\n\tproperties?: JsonSchemaPreviewProperty[];\n\tenumValues?: string[];\n}\n\nfunction JsonSchemaPreviewPropertyRow({\n\tproperty,\n\tlevel = 0,\n}: {\n\tproperty: JsonSchemaPreviewProperty;\n\tlevel?: number;\n}) {\n\tconst typeDisplay = property.isArray ? `${property.type}[]` : property.type;\n\n\treturn (\n\t\t<div>\n\t\t\t<div\n\t\t\t\tclassName=\"flex items-start gap-2 px-3 py-2 text-xs rounded-sm\"\n\t\t\t\tstyle={{ paddingLeft: `${8 + level * 16}px` }}\n\t\t\t>\n\t\t\t\t<div className=\"flex-1 text-left min-w-0\">\n\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<span className=\"font-mono font-semibold\">\n\t\t\t\t\t\t\t{property.name}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t{property.isRequired && (\n\t\t\t\t\t\t\t<span className=\"text-red-500 text-[10px]\">*</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t\t{property.description && (\n\t\t\t\t\t\t<div className=\"text-muted-foreground mt-0.5 text-[11px]\">\n\t\t\t\t\t\t\t{property.description}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{property.type === \"enum\" && property.enumValues && (\n\t\t\t\t\t\t<div className=\"text-muted-foreground mt-1 text-[10px]\">\n\t\t\t\t\t\t\tValues: {property.enumValues.join(\", \")}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<span\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"px-1.5 py-0.5 rounded text-[10px] font-medium shrink-0\",\n\t\t\t\t\t\t\"bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300\",\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t{typeDisplay}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t{property.properties && property.properties.length > 0 && (\n\t\t\t\t<div>\n\t\t\t\t\t{property.properties.map((nestedProp) => (\n\t\t\t\t\t\t<JsonSchemaPreviewPropertyRow\n\t\t\t\t\t\t\tkey={nestedProp.name}\n\t\t\t\t\t\t\tproperty={nestedProp}\n\t\t\t\t\t\t\tlevel={level + 1}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nexport function JsonSchemaPreviewEmpty({\n\tclassName,\n\t...props\n}: ComponentProps<\"div\">) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"border rounded-md p-4 text-xs text-muted-foreground text-center\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\tNo schema defined\n\t\t</div>\n\t);\n}\n",
			"type": "registry:ui"
		}
	]
}
