{"ast":null,"code":"var _jsxFileName = \"/Users/dwindown/CascadeProjects/developer-tools/src/components/StructuredEditor.js\",\n _s = $RefreshSig$();\nimport React, { useState } from 'react';\nimport { Plus, Minus, ChevronDown, ChevronRight, Type, Hash, ToggleLeft, List, Braces } from 'lucide-react';\nimport { jsxDEV as _jsxDEV, Fragment as _Fragment } from \"react/jsx-dev-runtime\";\nconst StructuredEditor = ({\n onDataChange,\n initialData = {}\n}) => {\n _s();\n const [data, setData] = useState(initialData);\n const [expandedNodes, setExpandedNodes] = useState(new Set(['root']));\n const updateData = newData => {\n setData(newData);\n onDataChange(newData);\n };\n const toggleNode = path => {\n const newExpanded = new Set(expandedNodes);\n if (newExpanded.has(path)) {\n newExpanded.delete(path);\n } else {\n newExpanded.add(path);\n }\n setExpandedNodes(newExpanded);\n };\n const addProperty = (obj, path) => {\n const newObj = {\n ...obj\n };\n const keys = Object.keys(newObj);\n const newKey = `property${keys.length + 1}`;\n newObj[newKey] = '';\n updateData(newObj);\n setExpandedNodes(new Set([...expandedNodes, path]));\n };\n const addArrayItem = (arr, path) => {\n const newArr = [...arr, ''];\n const pathParts = path.split('.');\n const newData = {\n ...data\n };\n let current = newData;\n for (let i = 1; i < pathParts.length - 1; i++) {\n current = current[pathParts[i]];\n }\n if (pathParts.length === 2) {\n newData[pathParts[1]] = newArr;\n } else {\n current[pathParts[pathParts.length - 1]] = newArr;\n }\n updateData(newData);\n };\n const removeProperty = (key, parentPath) => {\n const pathParts = parentPath.split('.');\n const newData = {\n ...data\n };\n let current = newData;\n for (let i = 1; i < pathParts.length; i++) {\n if (i === pathParts.length - 1) {\n delete current[key];\n } else {\n current = current[pathParts[i]];\n }\n }\n if (pathParts.length === 1) {\n delete newData[key];\n }\n updateData(newData);\n };\n const updateValue = (value, path) => {\n const pathParts = path.split('.');\n const newData = {\n ...data\n };\n let current = newData;\n for (let i = 1; i < pathParts.length - 1; i++) {\n current = current[pathParts[i]];\n }\n const key = pathParts[pathParts.length - 1];\n\n // Auto-detect type\n if (value === 'true' || value === 'false') {\n current[key] = value === 'true';\n } else if (value === 'null') {\n current[key] = null;\n } else if (!isNaN(value) && value !== '') {\n current[key] = Number(value);\n } else {\n current[key] = value;\n }\n updateData(newData);\n };\n const changeType = (newType, path) => {\n const pathParts = path.split('.');\n const newData = {\n ...data\n };\n let current = newData;\n for (let i = 1; i < pathParts.length - 1; i++) {\n current = current[pathParts[i]];\n }\n const key = pathParts[pathParts.length - 1];\n switch (newType) {\n case 'string':\n current[key] = '';\n break;\n case 'number':\n current[key] = 0;\n break;\n case 'boolean':\n current[key] = false;\n break;\n case 'array':\n current[key] = [];\n break;\n case 'object':\n current[key] = {};\n break;\n case 'null':\n current[key] = null;\n break;\n default:\n current[key] = '';\n }\n updateData(newData);\n setExpandedNodes(new Set([...expandedNodes, path]));\n };\n const renameKey = (oldKey, newKey, path) => {\n if (oldKey === newKey || !newKey.trim()) return;\n const pathParts = path.split('.');\n const newData = {\n ...data\n };\n let current = newData;\n\n // Navigate to parent object\n for (let i = 1; i < pathParts.length - 1; i++) {\n current = current[pathParts[i]];\n }\n\n // Check if new key already exists\n if (current.hasOwnProperty(newKey)) {\n return; // Don't rename if key already exists\n }\n\n // Rename the key\n const value = current[oldKey];\n delete current[oldKey];\n current[newKey] = value;\n updateData(newData);\n };\n const getTypeIcon = value => {\n if (value === null) return /*#__PURE__*/_jsxDEV(\"span\", {\n className: \"text-gray-500\",\n children: \"\\u2205\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 160,\n columnNumber: 32\n }, this);\n if (typeof value === 'string') return /*#__PURE__*/_jsxDEV(Type, {\n className: \"h-4 w-4 text-green-600\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 161,\n columnNumber: 43\n }, this);\n if (typeof value === 'number') return /*#__PURE__*/_jsxDEV(Hash, {\n className: \"h-4 w-4 text-blue-600\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 162,\n columnNumber: 43\n }, this);\n if (typeof value === 'boolean') return /*#__PURE__*/_jsxDEV(ToggleLeft, {\n className: \"h-4 w-4 text-purple-600\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 163,\n columnNumber: 44\n }, this);\n if (Array.isArray(value)) return /*#__PURE__*/_jsxDEV(List, {\n className: \"h-4 w-4 text-orange-600\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 164,\n columnNumber: 38\n }, this);\n if (typeof value === 'object') return /*#__PURE__*/_jsxDEV(Braces, {\n className: \"h-4 w-4 text-red-600\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 165,\n columnNumber: 43\n }, this);\n return /*#__PURE__*/_jsxDEV(Type, {\n className: \"h-4 w-4 text-gray-600\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 166,\n columnNumber: 12\n }, this);\n };\n const renderValue = (value, key, path, parentPath) => {\n const isExpanded = expandedNodes.has(path);\n const canExpand = typeof value === 'object' && value !== null;\n return /*#__PURE__*/_jsxDEV(\"div\", {\n className: \"ml-4 border-l border-gray-200 dark:border-gray-700 pl-4 mb-2\",\n children: [/*#__PURE__*/_jsxDEV(\"div\", {\n className: \"flex items-center space-x-2 mb-2\",\n children: [canExpand && /*#__PURE__*/_jsxDEV(\"button\", {\n onClick: () => toggleNode(path),\n className: \"p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded\",\n children: isExpanded ? /*#__PURE__*/_jsxDEV(ChevronDown, {\n className: \"h-4 w-4\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 182,\n columnNumber: 17\n }, this) : /*#__PURE__*/_jsxDEV(ChevronRight, {\n className: \"h-4 w-4\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 184,\n columnNumber: 17\n }, this)\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 177,\n columnNumber: 13\n }, this), !canExpand && /*#__PURE__*/_jsxDEV(\"div\", {\n className: \"w-6\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 189,\n columnNumber: 26\n }, this), /*#__PURE__*/_jsxDEV(\"div\", {\n className: \"flex flex-col sm:flex-row sm:items-center space-y-2 sm:space-y-0 sm:space-x-2 flex-1\",\n children: [/*#__PURE__*/_jsxDEV(\"div\", {\n className: \"flex items-center space-x-2 flex-1\",\n children: [getTypeIcon(value), /*#__PURE__*/_jsxDEV(\"input\", {\n type: \"text\",\n defaultValue: key,\n onBlur: e => {\n const newKey = e.target.value.trim();\n if (newKey && newKey !== key) {\n renameKey(key, newKey, path);\n }\n },\n onKeyDown: e => {\n if (e.key === 'Enter') {\n e.target.blur(); // Trigger blur to save changes\n }\n },\n className: \"px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 min-w-0 flex-1\",\n placeholder: \"Property name\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 195,\n columnNumber: 15\n }, this), /*#__PURE__*/_jsxDEV(\"span\", {\n className: \"text-gray-500 hidden sm:inline\",\n children: \":\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 213,\n columnNumber: 15\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 192,\n columnNumber: 13\n }, this), !canExpand ? /*#__PURE__*/_jsxDEV(\"input\", {\n type: \"text\",\n value: value === null ? 'null' : value === undefined ? '' : value.toString(),\n onChange: e => updateValue(e.target.value, path),\n className: \"flex-1 px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100\",\n placeholder: \"Value\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 217,\n columnNumber: 15\n }, this) : /*#__PURE__*/_jsxDEV(\"span\", {\n className: \"text-sm text-gray-600 dark:text-gray-400\",\n children: Array.isArray(value) ? `Array (${value.length} items)` : `Object (${Object.keys(value).length} properties)`\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 229,\n columnNumber: 15\n }, this), /*#__PURE__*/_jsxDEV(\"div\", {\n className: \"flex items-center space-x-2 sm:space-x-2\",\n children: [/*#__PURE__*/_jsxDEV(\"select\", {\n value: value === null ? 'null' : typeof value === 'string' ? 'string' : typeof value === 'number' ? 'number' : typeof value === 'boolean' ? 'boolean' : Array.isArray(value) ? 'array' : 'object',\n onChange: e => changeType(e.target.value, path),\n className: \"px-2 py-1 text-xs border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 min-w-0\",\n children: [/*#__PURE__*/_jsxDEV(\"option\", {\n value: \"string\",\n children: \"String\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 246,\n columnNumber: 17\n }, this), /*#__PURE__*/_jsxDEV(\"option\", {\n value: \"number\",\n children: \"Number\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 247,\n columnNumber: 17\n }, this), /*#__PURE__*/_jsxDEV(\"option\", {\n value: \"boolean\",\n children: \"Boolean\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 248,\n columnNumber: 17\n }, this), /*#__PURE__*/_jsxDEV(\"option\", {\n value: \"array\",\n children: \"Array\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 249,\n columnNumber: 17\n }, this), /*#__PURE__*/_jsxDEV(\"option\", {\n value: \"object\",\n children: \"Object\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 250,\n columnNumber: 17\n }, this), /*#__PURE__*/_jsxDEV(\"option\", {\n value: \"null\",\n children: \"Null\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 251,\n columnNumber: 17\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 235,\n columnNumber: 15\n }, this), /*#__PURE__*/_jsxDEV(\"button\", {\n onClick: () => removeProperty(key, parentPath),\n className: \"p-1 text-red-600 hover:bg-red-100 dark:hover:bg-red-900 rounded flex-shrink-0\",\n title: \"Remove property\",\n children: /*#__PURE__*/_jsxDEV(Minus, {\n className: \"h-4 w-4\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 259,\n columnNumber: 17\n }, this)\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 254,\n columnNumber: 15\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 234,\n columnNumber: 13\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 191,\n columnNumber: 11\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 175,\n columnNumber: 9\n }, this), canExpand && isExpanded && /*#__PURE__*/_jsxDEV(\"div\", {\n className: \"ml-6\",\n children: Array.isArray(value) ? /*#__PURE__*/_jsxDEV(_Fragment, {\n children: [value.map((item, index) => renderValue(item, index.toString(), `${path}.${index}`, path)), /*#__PURE__*/_jsxDEV(\"button\", {\n onClick: () => addArrayItem(value, path),\n className: \"flex items-center space-x-1 px-2 py-1 text-sm text-blue-600 hover:bg-blue-100 dark:hover:bg-blue-900 rounded\",\n children: [/*#__PURE__*/_jsxDEV(Plus, {\n className: \"h-4 w-4\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 276,\n columnNumber: 19\n }, this), /*#__PURE__*/_jsxDEV(\"span\", {\n children: \"Add Item\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 277,\n columnNumber: 19\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 272,\n columnNumber: 17\n }, this)]\n }, void 0, true) : /*#__PURE__*/_jsxDEV(_Fragment, {\n children: [Object.entries(value).map(([k, v]) => renderValue(v, k, `${path}.${k}`, path)), /*#__PURE__*/_jsxDEV(\"button\", {\n onClick: () => addProperty(value, path),\n className: \"flex items-center space-x-1 px-2 py-1 text-sm text-blue-600 hover:bg-blue-100 dark:hover:bg-blue-900 rounded\",\n children: [/*#__PURE__*/_jsxDEV(Plus, {\n className: \"h-4 w-4\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 289,\n columnNumber: 19\n }, this), /*#__PURE__*/_jsxDEV(\"span\", {\n children: \"Add Property\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 290,\n columnNumber: 19\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 285,\n columnNumber: 17\n }, this)]\n }, void 0, true)\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 266,\n columnNumber: 11\n }, this)]\n }, path, true, {\n fileName: _jsxFileName,\n lineNumber: 174,\n columnNumber: 7\n }, this);\n };\n return /*#__PURE__*/_jsxDEV(\"div\", {\n className: \"border border-gray-300 dark:border-gray-600 rounded-lg p-4 bg-white dark:bg-gray-800 min-h-96\",\n children: [/*#__PURE__*/_jsxDEV(\"div\", {\n className: \"flex items-center justify-between mb-4\",\n children: [/*#__PURE__*/_jsxDEV(\"h3\", {\n className: \"text-lg font-medium text-gray-900 dark:text-gray-100\",\n children: \"Structured Data Editor\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 303,\n columnNumber: 9\n }, this), /*#__PURE__*/_jsxDEV(\"button\", {\n onClick: () => addProperty(data, 'root'),\n className: \"flex items-center space-x-1 px-3 py-1 text-sm bg-blue-600 text-white rounded hover:bg-blue-700\",\n children: [/*#__PURE__*/_jsxDEV(Plus, {\n className: \"h-4 w-4\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 308,\n columnNumber: 11\n }, this), /*#__PURE__*/_jsxDEV(\"span\", {\n children: \"Add Property\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 309,\n columnNumber: 11\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 304,\n columnNumber: 9\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 302,\n columnNumber: 7\n }, this), /*#__PURE__*/_jsxDEV(\"div\", {\n className: \"overflow-y-auto\",\n style: {\n maxHeight: 'calc(24rem - 4rem)'\n },\n children: Object.keys(data).length === 0 ? /*#__PURE__*/_jsxDEV(\"div\", {\n className: \"text-center text-gray-500 dark:text-gray-400 py-8\",\n children: [/*#__PURE__*/_jsxDEV(Braces, {\n className: \"h-12 w-12 mx-auto mb-2 opacity-50\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 316,\n columnNumber: 13\n }, this), /*#__PURE__*/_jsxDEV(\"p\", {\n children: \"No properties yet. Click \\\"Add Property\\\" to start building your data structure.\"\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 317,\n columnNumber: 13\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 315,\n columnNumber: 11\n }, this) : Object.entries(data).map(([key, value]) => renderValue(value, key, `root.${key}`, 'root'))\n }, void 0, false, {\n fileName: _jsxFileName,\n lineNumber: 313,\n columnNumber: 7\n }, this)]\n }, void 0, true, {\n fileName: _jsxFileName,\n lineNumber: 301,\n columnNumber: 5\n }, this);\n};\n_s(StructuredEditor, \"CynZdsGZU1lgNsY7J0734MKTPtE=\");\n_c = StructuredEditor;\nexport default StructuredEditor;\nvar _c;\n$RefreshReg$(_c, \"StructuredEditor\");","map":{"version":3,"names":["React","useState","Plus","Minus","ChevronDown","ChevronRight","Type","Hash","ToggleLeft","List","Braces","jsxDEV","_jsxDEV","Fragment","_Fragment","StructuredEditor","onDataChange","initialData","_s","data","setData","expandedNodes","setExpandedNodes","Set","updateData","newData","toggleNode","path","newExpanded","has","delete","add","addProperty","obj","newObj","keys","Object","newKey","length","addArrayItem","arr","newArr","pathParts","split","current","i","removeProperty","key","parentPath","updateValue","value","isNaN","Number","changeType","newType","renameKey","oldKey","trim","hasOwnProperty","getTypeIcon","className","children","fileName","_jsxFileName","lineNumber","columnNumber","Array","isArray","renderValue","isExpanded","canExpand","onClick","type","defaultValue","onBlur","e","target","onKeyDown","blur","placeholder","undefined","toString","onChange","title","map","item","index","entries","k","v","style","maxHeight","_c","$RefreshReg$"],"sources":["/Users/dwindown/CascadeProjects/developer-tools/src/components/StructuredEditor.js"],"sourcesContent":["import React, { useState } from 'react';\nimport { Plus, Minus, ChevronDown, ChevronRight, Type, Hash, ToggleLeft, List, Braces } from 'lucide-react';\n\nconst StructuredEditor = ({ onDataChange, initialData = {} }) => {\n const [data, setData] = useState(initialData);\n const [expandedNodes, setExpandedNodes] = useState(new Set(['root']));\n\n const updateData = (newData) => {\n setData(newData);\n onDataChange(newData);\n };\n\n const toggleNode = (path) => {\n const newExpanded = new Set(expandedNodes);\n if (newExpanded.has(path)) {\n newExpanded.delete(path);\n } else {\n newExpanded.add(path);\n }\n setExpandedNodes(newExpanded);\n };\n\n const addProperty = (obj, path) => {\n const newObj = { ...obj };\n const keys = Object.keys(newObj);\n const newKey = `property${keys.length + 1}`;\n newObj[newKey] = '';\n updateData(newObj);\n setExpandedNodes(new Set([...expandedNodes, path]));\n };\n\n const addArrayItem = (arr, path) => {\n const newArr = [...arr, ''];\n const pathParts = path.split('.');\n const newData = { ...data };\n let current = newData;\n \n for (let i = 1; i < pathParts.length - 1; i++) {\n current = current[pathParts[i]];\n }\n \n if (pathParts.length === 2) {\n newData[pathParts[1]] = newArr;\n } else {\n current[pathParts[pathParts.length - 1]] = newArr;\n }\n \n updateData(newData);\n };\n\n const removeProperty = (key, parentPath) => {\n const pathParts = parentPath.split('.');\n const newData = { ...data };\n let current = newData;\n \n for (let i = 1; i < pathParts.length; i++) {\n if (i === pathParts.length - 1) {\n delete current[key];\n } else {\n current = current[pathParts[i]];\n }\n }\n \n if (pathParts.length === 1) {\n delete newData[key];\n }\n \n updateData(newData);\n };\n\n const updateValue = (value, path) => {\n const pathParts = path.split('.');\n const newData = { ...data };\n let current = newData;\n \n for (let i = 1; i < pathParts.length - 1; i++) {\n current = current[pathParts[i]];\n }\n \n const key = pathParts[pathParts.length - 1];\n \n // Auto-detect type\n if (value === 'true' || value === 'false') {\n current[key] = value === 'true';\n } else if (value === 'null') {\n current[key] = null;\n } else if (!isNaN(value) && value !== '') {\n current[key] = Number(value);\n } else {\n current[key] = value;\n }\n \n updateData(newData);\n };\n\n const changeType = (newType, path) => {\n const pathParts = path.split('.');\n const newData = { ...data };\n let current = newData;\n \n for (let i = 1; i < pathParts.length - 1; i++) {\n current = current[pathParts[i]];\n }\n \n const key = pathParts[pathParts.length - 1];\n \n switch (newType) {\n case 'string':\n current[key] = '';\n break;\n case 'number':\n current[key] = 0;\n break;\n case 'boolean':\n current[key] = false;\n break;\n case 'array':\n current[key] = [];\n break;\n case 'object':\n current[key] = {};\n break;\n case 'null':\n current[key] = null;\n break;\n default:\n current[key] = '';\n }\n \n updateData(newData);\n setExpandedNodes(new Set([...expandedNodes, path]));\n };\n\n const renameKey = (oldKey, newKey, path) => {\n if (oldKey === newKey || !newKey.trim()) return;\n \n const pathParts = path.split('.');\n const newData = { ...data };\n let current = newData;\n \n // Navigate to parent object\n for (let i = 1; i < pathParts.length - 1; i++) {\n current = current[pathParts[i]];\n }\n \n // Check if new key already exists\n if (current.hasOwnProperty(newKey)) {\n return; // Don't rename if key already exists\n }\n \n // Rename the key\n const value = current[oldKey];\n delete current[oldKey];\n current[newKey] = value;\n \n updateData(newData);\n };\n\n const getTypeIcon = (value) => {\n if (value === null) return ∅;\n if (typeof value === 'string') return ;\n if (typeof value === 'object') return
No properties yet. Click \"Add Property\" to start building your data structure.
\n