From f547d385392ff4f8fe29e8b05a5afdf54264f616 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sun, 18 Jan 2026 15:48:29 +0000 Subject: [PATCH] things --- .claude/settings.local.json | 9 + docs/COMPONENT_CONVERSION_ANALYSIS.md | 262 ++++++++++ docs/HYBRID_ARCHITECTURE.md | 471 ++++++++++++++++++ docs/JSON_ARCHITECTURE.md | 388 +++++++++++++++ src/components/JSONSchemaPageLoader.tsx | 25 + src/config/get-enabled-pages.ts | 17 + src/config/get-page-by-id.ts | 9 + src/config/get-page-config.ts | 9 + src/config/get-page-shortcuts.ts | 30 ++ src/config/pages/actions/create-action.json | 4 + src/config/pages/actions/delete-action.json | 4 + src/config/pages/actions/navigate-action.json | 6 + src/config/pages/actions/update-action.json | 4 + .../pages/atomic-library-showcase-page.json | 17 + src/config/pages/atoms/alert.json | 6 + src/config/pages/atoms/badge.json | 6 + .../pages/atoms/button-destructive.json | 6 + src/config/pages/atoms/button-outline.json | 6 + src/config/pages/atoms/card-content.json | 3 + src/config/pages/atoms/card-footer.json | 3 + src/config/pages/atoms/card-header.json | 3 + src/config/pages/atoms/card.json | 3 + src/config/pages/atoms/div-flex-col.json | 6 + src/config/pages/atoms/div-flex.json | 6 + src/config/pages/atoms/div-grid.json | 6 + src/config/pages/atoms/heading-1.json | 7 + src/config/pages/atoms/heading-2.json | 7 + src/config/pages/atoms/icon-base.json | 7 + src/config/pages/atoms/icon-folder.json | 7 + src/config/pages/atoms/input-text.json | 6 + src/config/pages/atoms/label.json | 3 + src/config/pages/atoms/loading-spinner.json | 7 + src/config/pages/atoms/section.json | 3 + src/config/pages/atoms/separator.json | 6 + src/config/pages/atoms/text-muted.json | 6 + src/config/pages/atoms/text-small.json | 7 + src/config/pages/atoms/text.json | 3 + src/config/pages/atoms/textarea.json | 6 + src/config/pages/code-editor-page.json | 17 + .../pages/component-tree-builder-page.json | 17 + .../pages/component-tree-manager-page.json | 17 + src/config/pages/components-page.json | 30 ++ .../pages/components/button-primary.json | 7 + .../pages/components/button-secondary.json | 7 + .../pages/components/card-container.json | 14 + src/config/pages/components/form-input.json | 17 + src/config/pages/components/grid-2-col.json | 7 + src/config/pages/components/grid-3-col.json | 7 + src/config/pages/components/page-header.json | 24 + src/config/pages/components/stat-card.json | 30 ++ .../pages/conflict-resolution-page.json | 17 + src/config/pages/dashboard-simple.json | 30 ++ src/config/pages/data-binding-page.json | 23 + src/config/pages/data-sources/kv-storage.json | 5 + .../pages/docker-build-debugger-page.json | 17 + src/config/pages/docs-page.json | 23 + src/config/pages/documentation-view-page.json | 17 + src/config/pages/error-panel-page.json | 17 + src/config/pages/errors-page.json | 23 + src/config/pages/favicon-designer-page.json | 17 + src/config/pages/favicon-page.json | 23 + src/config/pages/feature-idea-cloud-page.json | 17 + .../pages/feature-toggle-settings-page.json | 17 + src/config/pages/features-page.json | 23 + src/config/pages/flask-page.json | 38 ++ src/config/pages/home-page.json | 5 + src/config/pages/ideas-page.json | 23 + .../json-component-tree-manager-page.json | 17 + src/config/pages/json-ui-page.json | 23 + src/config/pages/json-ui-showcase-page.json | 17 + src/config/pages/lambda-designer-page.json | 17 + src/config/pages/lambdas-page.json | 54 ++ src/config/pages/layouts/single-column.json | 3 + src/config/pages/model-designer-page.json | 17 + src/config/pages/models-page.json | 119 +++++ src/config/pages/molecules/action-bar.json | 17 + src/config/pages/molecules/app-branding.json | 25 + src/config/pages/molecules/breadcrumb.json | 23 + .../pages/molecules/card-with-actions.json | 30 ++ .../pages/molecules/component-palette.json | 24 + .../pages/molecules/component-tree.json | 7 + .../pages/molecules/dashboard-header.json | 24 + src/config/pages/molecules/data-card.json | 18 + .../pages/molecules/editor-toolbar.json | 23 + .../pages/molecules/empty-editor-state.json | 27 + src/config/pages/molecules/empty-state.json | 33 ++ src/config/pages/molecules/file-tabs.json | 7 + src/config/pages/molecules/form-field.json | 23 + .../pages/molecules/label-with-badge.json | 29 ++ src/config/pages/molecules/loading-state.json | 21 + .../pages/molecules/page-header-content.json | 30 ++ .../pages/molecules/page-header-standard.json | 19 + .../pages/molecules/save-indicator.json | 69 +++ .../molecules/schema-editor-status-bar.json | 20 + src/config/pages/molecules/search-input.json | 78 +++ .../pages/molecules/stat-card-base.json | 24 + .../pages/molecules/stat-card-components.json | 26 + .../pages/molecules/stat-card-files.json | 26 + .../pages/molecules/stat-card-models.json | 26 + src/config/pages/molecules/stats-grid.json | 18 + .../pages/molecules/toolbar-with-actions.json | 22 + src/config/pages/organisms/app-header.json | 26 + .../pages/organisms/empty-canvas-state.json | 59 +++ .../pages/organisms/navigation-menu.json | 23 + src/config/pages/organisms/page-header.json | 13 + .../pages/organisms/schema-editor-canvas.json | 24 + .../pages/organisms/schema-editor-layout.json | 21 + .../schema-editor-properties-panel.json | 31 ++ .../organisms/schema-editor-sidebar.json | 20 + .../pages/persistence-dashboard-page.json | 17 + .../pages/persistence-example-page.json | 17 + src/config/pages/persistence-page.json | 23 + src/config/pages/playwright-page.json | 36 ++ src/config/pages/project-dashboard.json | 17 + src/config/pages/pwa-page.json | 23 + src/config/pages/pwa-settings-page.json | 17 + src/config/pages/sass-showcase-page.json | 17 + src/config/pages/schema-editor-page.json | 23 + src/config/pages/settings-page.json | 121 +++++ src/config/pages/storybook-page.json | 36 ++ src/config/pages/style-designer-page.json | 17 + src/config/pages/styling-page.json | 30 ++ src/config/pages/template-selector-page.json | 17 + src/config/pages/templates/standard-page.json | 19 + src/config/pages/unit-tests-page.json | 36 ++ src/config/pages/workflow-designer-page.json | 17 + src/config/pages/workflows-page.json | 73 +++ src/config/resolve-props.ts | 60 +++ src/hooks/use-schema-loader.ts | 30 ++ src/types/page-config.ts | 18 + src/types/pages-config.ts | 5 + src/types/prop-config.ts | 4 + src/types/resizable-config.ts | 14 + src/types/theme-schema.ts | 90 ++++ 134 files changed, 3863 insertions(+) create mode 100644 .claude/settings.local.json create mode 100644 docs/COMPONENT_CONVERSION_ANALYSIS.md create mode 100644 docs/HYBRID_ARCHITECTURE.md create mode 100644 docs/JSON_ARCHITECTURE.md create mode 100644 src/components/JSONSchemaPageLoader.tsx create mode 100644 src/config/get-enabled-pages.ts create mode 100644 src/config/get-page-by-id.ts create mode 100644 src/config/get-page-config.ts create mode 100644 src/config/get-page-shortcuts.ts create mode 100644 src/config/pages/actions/create-action.json create mode 100644 src/config/pages/actions/delete-action.json create mode 100644 src/config/pages/actions/navigate-action.json create mode 100644 src/config/pages/actions/update-action.json create mode 100644 src/config/pages/atomic-library-showcase-page.json create mode 100644 src/config/pages/atoms/alert.json create mode 100644 src/config/pages/atoms/badge.json create mode 100644 src/config/pages/atoms/button-destructive.json create mode 100644 src/config/pages/atoms/button-outline.json create mode 100644 src/config/pages/atoms/card-content.json create mode 100644 src/config/pages/atoms/card-footer.json create mode 100644 src/config/pages/atoms/card-header.json create mode 100644 src/config/pages/atoms/card.json create mode 100644 src/config/pages/atoms/div-flex-col.json create mode 100644 src/config/pages/atoms/div-flex.json create mode 100644 src/config/pages/atoms/div-grid.json create mode 100644 src/config/pages/atoms/heading-1.json create mode 100644 src/config/pages/atoms/heading-2.json create mode 100644 src/config/pages/atoms/icon-base.json create mode 100644 src/config/pages/atoms/icon-folder.json create mode 100644 src/config/pages/atoms/input-text.json create mode 100644 src/config/pages/atoms/label.json create mode 100644 src/config/pages/atoms/loading-spinner.json create mode 100644 src/config/pages/atoms/section.json create mode 100644 src/config/pages/atoms/separator.json create mode 100644 src/config/pages/atoms/text-muted.json create mode 100644 src/config/pages/atoms/text-small.json create mode 100644 src/config/pages/atoms/text.json create mode 100644 src/config/pages/atoms/textarea.json create mode 100644 src/config/pages/code-editor-page.json create mode 100644 src/config/pages/component-tree-builder-page.json create mode 100644 src/config/pages/component-tree-manager-page.json create mode 100644 src/config/pages/components-page.json create mode 100644 src/config/pages/components/button-primary.json create mode 100644 src/config/pages/components/button-secondary.json create mode 100644 src/config/pages/components/card-container.json create mode 100644 src/config/pages/components/form-input.json create mode 100644 src/config/pages/components/grid-2-col.json create mode 100644 src/config/pages/components/grid-3-col.json create mode 100644 src/config/pages/components/page-header.json create mode 100644 src/config/pages/components/stat-card.json create mode 100644 src/config/pages/conflict-resolution-page.json create mode 100644 src/config/pages/dashboard-simple.json create mode 100644 src/config/pages/data-binding-page.json create mode 100644 src/config/pages/data-sources/kv-storage.json create mode 100644 src/config/pages/docker-build-debugger-page.json create mode 100644 src/config/pages/docs-page.json create mode 100644 src/config/pages/documentation-view-page.json create mode 100644 src/config/pages/error-panel-page.json create mode 100644 src/config/pages/errors-page.json create mode 100644 src/config/pages/favicon-designer-page.json create mode 100644 src/config/pages/favicon-page.json create mode 100644 src/config/pages/feature-idea-cloud-page.json create mode 100644 src/config/pages/feature-toggle-settings-page.json create mode 100644 src/config/pages/features-page.json create mode 100644 src/config/pages/flask-page.json create mode 100644 src/config/pages/home-page.json create mode 100644 src/config/pages/ideas-page.json create mode 100644 src/config/pages/json-component-tree-manager-page.json create mode 100644 src/config/pages/json-ui-page.json create mode 100644 src/config/pages/json-ui-showcase-page.json create mode 100644 src/config/pages/lambda-designer-page.json create mode 100644 src/config/pages/lambdas-page.json create mode 100644 src/config/pages/layouts/single-column.json create mode 100644 src/config/pages/model-designer-page.json create mode 100644 src/config/pages/models-page.json create mode 100644 src/config/pages/molecules/action-bar.json create mode 100644 src/config/pages/molecules/app-branding.json create mode 100644 src/config/pages/molecules/breadcrumb.json create mode 100644 src/config/pages/molecules/card-with-actions.json create mode 100644 src/config/pages/molecules/component-palette.json create mode 100644 src/config/pages/molecules/component-tree.json create mode 100644 src/config/pages/molecules/dashboard-header.json create mode 100644 src/config/pages/molecules/data-card.json create mode 100644 src/config/pages/molecules/editor-toolbar.json create mode 100644 src/config/pages/molecules/empty-editor-state.json create mode 100644 src/config/pages/molecules/empty-state.json create mode 100644 src/config/pages/molecules/file-tabs.json create mode 100644 src/config/pages/molecules/form-field.json create mode 100644 src/config/pages/molecules/label-with-badge.json create mode 100644 src/config/pages/molecules/loading-state.json create mode 100644 src/config/pages/molecules/page-header-content.json create mode 100644 src/config/pages/molecules/page-header-standard.json create mode 100644 src/config/pages/molecules/save-indicator.json create mode 100644 src/config/pages/molecules/schema-editor-status-bar.json create mode 100644 src/config/pages/molecules/search-input.json create mode 100644 src/config/pages/molecules/stat-card-base.json create mode 100644 src/config/pages/molecules/stat-card-components.json create mode 100644 src/config/pages/molecules/stat-card-files.json create mode 100644 src/config/pages/molecules/stat-card-models.json create mode 100644 src/config/pages/molecules/stats-grid.json create mode 100644 src/config/pages/molecules/toolbar-with-actions.json create mode 100644 src/config/pages/organisms/app-header.json create mode 100644 src/config/pages/organisms/empty-canvas-state.json create mode 100644 src/config/pages/organisms/navigation-menu.json create mode 100644 src/config/pages/organisms/page-header.json create mode 100644 src/config/pages/organisms/schema-editor-canvas.json create mode 100644 src/config/pages/organisms/schema-editor-layout.json create mode 100644 src/config/pages/organisms/schema-editor-properties-panel.json create mode 100644 src/config/pages/organisms/schema-editor-sidebar.json create mode 100644 src/config/pages/persistence-dashboard-page.json create mode 100644 src/config/pages/persistence-example-page.json create mode 100644 src/config/pages/persistence-page.json create mode 100644 src/config/pages/playwright-page.json create mode 100644 src/config/pages/project-dashboard.json create mode 100644 src/config/pages/pwa-page.json create mode 100644 src/config/pages/pwa-settings-page.json create mode 100644 src/config/pages/sass-showcase-page.json create mode 100644 src/config/pages/schema-editor-page.json create mode 100644 src/config/pages/settings-page.json create mode 100644 src/config/pages/storybook-page.json create mode 100644 src/config/pages/style-designer-page.json create mode 100644 src/config/pages/styling-page.json create mode 100644 src/config/pages/template-selector-page.json create mode 100644 src/config/pages/templates/standard-page.json create mode 100644 src/config/pages/unit-tests-page.json create mode 100644 src/config/pages/workflow-designer-page.json create mode 100644 src/config/pages/workflows-page.json create mode 100644 src/config/resolve-props.ts create mode 100644 src/hooks/use-schema-loader.ts create mode 100644 src/types/page-config.ts create mode 100644 src/types/pages-config.ts create mode 100644 src/types/prop-config.ts create mode 100644 src/types/resizable-config.ts create mode 100644 src/types/theme-schema.ts diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..7f194d0 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(ls:*)", + "Bash(find:*)", + "Bash(grep:*)" + ] + } +} diff --git a/docs/COMPONENT_CONVERSION_ANALYSIS.md b/docs/COMPONENT_CONVERSION_ANALYSIS.md new file mode 100644 index 0000000..d2ca79e --- /dev/null +++ b/docs/COMPONENT_CONVERSION_ANALYSIS.md @@ -0,0 +1,262 @@ +# Component Conversion Analysis + +## Analysis of 68 React Components + +After analyzing all 68 organism and molecule components, here's what can be converted to JSON: + +### Categories + +#### ✅ Fully Convertible to JSON (48 components) + +These are presentational components with props, conditional rendering, and simple event handlers: + +**Molecules (35):** +1. `LabelWithBadge` - ✅ Converted +2. `LoadingState` - ✅ Converted +3. `SaveIndicator` - ✅ Converted (computed sources replace hook) +4. `SearchInput` - ✅ Converted +5. `AppBranding` - Props + conditionals +6. `ActionBar` - Layout + buttons +7. `Breadcrumb` - ✅ Already converted +8. `DataCard` - ✅ Already converted +9. `EmptyState` - ✅ Already converted +10. `EmptyEditorState` - ✅ Already converted +11. `FileTabs` - ✅ Already converted +12. `NavigationGroupHeader` - Collapse trigger + state +13. `NavigationItem` - Button with active state +14. `PageHeaderContent` - Layout composition +15. `ToolbarButton` - Tooltip + IconButton +16. `TreeListHeader` - Buttons with events +17. `ComponentTreeEmptyState` - Config + icon lookup +18. `ComponentTreeHeader` - Counts + expand/collapse +19. `PropertyEditorEmptyState` - Config + icon lookup +20. `PropertyEditorHeader` - Title + count +21. `PropertyEditorSection` - Collapsible section +22. `DataSourceIdField` - Input with validation display +23. `KvSourceFields` - Form fields +24. `StaticSourceFields` - Form fields +25. `ComputedSourceFields` - Form fields +26. `GitHubBuildStatus` - Status display + polling +27. `LoadingFallback` - Spinner + message +28. `MonacoEditorPanel` - Layout wrapper (not editor itself) +29. `SearchBar` - SearchInput wrapper +30. `SeedDataManager` - Form + buttons (logic in parent) +31. `StorageSettings` - Form fields +32. `TreeCard` - Card + tree display +33. `TreeFormDialog` - Dialog with form (validation in parent) +34. `EditorActions` - Button group +35. `EditorToolbar` - Toolbar layout + +**Organisms (13):** +1. `AppHeader` - ✅ Already converted +2. `EmptyCanvasState` - ✅ Already converted +3. `NavigationMenu` - ✅ Already converted +4. `PageHeader` - ✅ Already converted +5. `SchemaEditorLayout` - ✅ Already converted +6. `SchemaEditorSidebar` - ✅ Already converted +7. `SchemaEditorCanvas` - ✅ Already converted +8. `SchemaEditorPropertiesPanel` - ✅ Already converted +9. `SchemaEditorStatusBar` - Status display +10. `SchemaEditorToolbar` - Toolbar with actions +11. `ToolbarActions` - Action buttons +12. `SchemaCodeViewer` - Tabs + code display +13. `TreeListPanel` - List display + +#### ⚠️ Needs Wrapper (Complex Hooks) (12 components) + +These use hooks but the hook logic can be extracted to data sources or remain in a thin wrapper: + +**Molecules (10):** +1. `BindingEditor` - Form with `useForm` hook → Extract to form state +2. `ComponentBindingDialog` - Dialog with `useForm` → Extract to form state +3. `DataSourceEditorDialog` - Complex form + validation → Wrapper + JSON form +4. `PropertyEditor` - Dynamic form generation → Computed source for fields +5. `ComponentPalette` - Search + filter → Computed source +6. `CanvasRenderer` - Recursive rendering → Could be JSON with loop support +7. `ComponentTree` - Tree state + drag/drop → State machine in JSON +8. `ComponentTreeNodes` - Recursive nodes → Loop construct +9. `CodeExplanationDialog` - Dialog + API call → Dialog JSON + API action +10. `DataSourceCard` - Card with actions + state → Separate state, JSON layout + +**Organisms (2):** +1. `DataSourceManager` - Complex CRUD + hook → Extract `useDataSourceManager` logic +2. `JSONUIShowcase` - Examples display → Convert examples to JSON schema + +#### ❌ Must Stay React (8 components) + +These have imperative APIs, complex recursion, or third-party integration: + +**Molecules (6):** +1. `LazyMonacoEditor` - Monaco integration (refs, imperative API) +2. `LazyInlineMonacoEditor` - Monaco integration +3. `MonacoEditorPanel` - Monaco wrapper +4. `LazyBarChart` - Recharts integration +5. `LazyLineChart` - Recharts integration +6. `LazyD3BarChart` - D3.js integration (imperative DOM manipulation) + +**Organisms (2):** +1. `SchemaEditor` - Complex editor with drag-drop, undo/redo state machine +2. `DataBindingDesigner` - Visual flow editor with canvas manipulation + +## Conversion Statistics + +| Category | Count | Percentage | +|----------|-------|------------| +| ✅ Fully Convertible | 48 | 71% | +| ⚠️ Needs Wrapper | 12 | 18% | +| ❌ Must Stay React | 8 | 11% | +| **Total** | **68** | **100%** | + +## Key Insights + +### 1. Most Components Are Presentational +71% of components are pure presentation + simple logic that JSON can handle with: +- Data binding +- Computed sources +- Conditional rendering +- Event actions +- Loops (for lists) + +### 2. Hooks Aren't a Blocker +Even components with hooks like `useSaveIndicator` can be converted: +- Time-based logic → Computed sources with polling +- Form state → Form data sources +- Local UI state → Page-level state + +### 3. True Blockers +Only 8 components (11%) genuinely need React: +- Third-party library integrations (Monaco, D3, Recharts) +- Complex state machines (drag-drop, undo/redo) +- Imperative DOM manipulation +- Recursive algorithms (though loops might handle some) + +### 4. Wrapper Pattern +The 12 "needs wrapper" components can have thin React wrappers that: +- Extract hooks to data source utilities +- Convert to JSON-configurable components +- Keep complex logic centralized + +Example: +```tsx +// Thin wrapper +export function FormDialogWrapper({ schema, onSubmit }) { + const form = useForm() + return +} +``` + +```json +// JSON configures it +{ + "type": "FormDialogWrapper", + "props": { + "schema": { "$ref": "./schemas/user-form.json" } + } +} +``` + +## Recommended Conversion Priority + +### Phase 1: Low-Hanging Fruit (35 molecules) +Convert all presentational molecules that are just composition: +- AppBranding, ActionBar, ToolbarButton, etc. +- **Impact**: Eliminate 51% of React components + +### Phase 2: Organisms (13) +Convert layout organisms: +- TreeListPanel, SchemaCodeViewer, etc. +- **Impact**: Eliminate 70% of React components + +### Phase 3: Extract Hooks (10 molecules) +Create data source utilities and convert: +- BindingEditor, ComponentPalette, etc. +- **Impact**: Eliminate 85% of React components + +### Phase 4: Wrappers (2 organisms) +Create thin wrappers for complex components: +- DataSourceManager, JSONUIShowcase +- **Impact**: 89% conversion + +### Final State +- **8 React components** (third-party integrations + complex editors) +- **60 JSON components** (89% of current React code) +- **100% JSON page definitions** (already achieved) + +## Implementation Patterns + +### Pattern 1: Simple Conversion +```tsx +// React +export function LabelWithBadge({ label, badge }) { + return ( + + {label} + {badge && {badge}} + + ) +} +``` + +```json +// JSON +{ + "type": "div", + "className": "flex gap-2", + "children": [ + { "type": "Text", "dataBinding": { "children": { "source": "label" } } }, + { + "type": "Badge", + "conditional": { "source": "badge", "operator": "truthy" }, + "dataBinding": { "children": { "source": "badge" } } + } + ] +} +``` + +### Pattern 2: Hook Extraction +```tsx +// React (before) +export function SaveIndicator({ lastSaved }) { + const { timeAgo, isRecent } = useSaveIndicator(lastSaved) + return
{isRecent ? 'Saved' : timeAgo}
+} +``` + +```json +// JSON (after) - hook logic → computed source +{ + "dataSources": [ + { + "id": "isRecent", + "type": "computed", + "compute": "(data) => Date.now() - data.lastSaved < 3000" + } + ], + "type": "div", + "dataBinding": { + "children": { + "source": "isRecent", + "transform": "(isRecent, data) => isRecent ? 'Saved' : data.timeAgo" + } + } +} +``` + +### Pattern 3: Wrapper for Complex Logic +```tsx +// Thin React wrapper +export function DataSourceManagerWrapper(props) { + const manager = useDataSourceManager(props.dataSources) + return +} +``` + +## Next Steps + +1. ✅ Convert 35 simple molecules to JSON +2. ✅ Convert 13 layout organisms to JSON +3. ⚠️ Extract hooks to utilities for 10 components +4. ⚠️ Create wrappers for 2 complex organisms +5. ❌ Keep 8 third-party integrations as React + +**Target: 60/68 components in JSON (89% conversion)** diff --git a/docs/HYBRID_ARCHITECTURE.md b/docs/HYBRID_ARCHITECTURE.md new file mode 100644 index 0000000..e654863 --- /dev/null +++ b/docs/HYBRID_ARCHITECTURE.md @@ -0,0 +1,471 @@ +# Hybrid Architecture: JSON + React + +## The Power of Both Worlds + +This platform uses a **hybrid architecture** where JSON handles declarative UI composition while React provides the imperative implementation layer. This gives you the best of both worlds: + +- **JSON** for structure, composition, and configuration +- **React** for complex logic, hooks, events, and interactivity + +## What JSON Can't (and Shouldn't) Replace + +### 1. Hooks +React hooks manage complex stateful logic that can't be represented declaratively: + +```tsx +// ❌ Cannot be JSON +function useDataSourceManager(dataSources: DataSource[]) { + const [localSources, setLocalSources] = useState(dataSources) + const [editingSource, setEditingSource] = useState(null) + + useEffect(() => { + // Sync with external API + syncDataSources(localSources) + }, [localSources]) + + const getDependents = useCallback((id: string) => { + return localSources.filter(ds => ds.dependencies?.includes(id)) + }, [localSources]) + + return { localSources, editingSource, getDependents, ... } +} +``` + +**Why React?** Hooks encapsulate complex imperative logic: side effects, memoization, refs, context. JSON is declarative and can't express these patterns. + +### 2. Event Handlers with Complex Logic +Simple actions work in JSON, but complex event handling needs code: + +```tsx +// ✅ Simple actions in JSON +{ + "events": [{ + "event": "onClick", + "actions": [ + { "type": "setState", "target": "count", "value": 1 }, + { "type": "toast", "title": "Clicked!" } + ] + }] +} + +// ❌ Complex logic needs React +function handleFileUpload(event: React.ChangeEvent) { + const file = event.target.files?.[0] + if (!file) return + + // Validate file type + const validTypes = ['image/png', 'image/jpeg', 'image/svg+xml'] + if (!validTypes.includes(file.type)) { + toast.error('Invalid file type') + return + } + + // Check file size + const maxSize = 5 * 1024 * 1024 // 5MB + if (file.size > maxSize) { + toast.error('File too large') + return + } + + // Convert to base64, compress, upload + compressImage(file).then(compressed => { + uploadToServer(compressed).then(url => { + updateState({ faviconUrl: url }) + toast.success('Uploaded!') + }) + }) +} +``` + +**Why React?** Branching logic, async operations, error handling, file processing. JSON actions are linear and synchronous. + +### 3. Classes and Interfaces +Type systems and OOP patterns require TypeScript: + +```tsx +// ❌ Cannot be JSON +export interface DataSource { + id: string + type: DataSourceType + dependencies?: string[] + compute?: string +} + +export class ThemeManager { + private themes: Map + private listeners: Set + + constructor(initialThemes: Theme[]) { + this.themes = new Map(initialThemes.map(t => [t.id, t])) + this.listeners = new Set() + } + + applyTheme(themeId: string): void { + const theme = this.themes.get(themeId) + if (!theme) throw new Error(`Theme ${themeId} not found`) + + // Apply CSS variables + Object.entries(theme.colors).forEach(([key, value]) => { + document.documentElement.style.setProperty(`--${key}`, value) + }) + + // Notify listeners + this.listeners.forEach(listener => listener.onThemeChange(theme)) + } +} +``` + +**Why React/TS?** Type safety, encapsulation, methods, private state. JSON is just data. + +### 4. Complex Rendering Logic +Conditional rendering with complex business rules: + +```tsx +// ❌ Cannot be JSON +function ComponentTree({ components }: ComponentTreeProps) { + const renderNode = (component: Component, depth: number): ReactNode => { + const hasChildren = component.children && component.children.length > 0 + const isExpanded = expandedNodes.has(component.id) + const isDragging = draggedNode === component.id + const isDropTarget = dropTarget === component.id + + // Determine visual state + const className = cn( + 'tree-node', + { 'tree-node--expanded': isExpanded }, + { 'tree-node--dragging': isDragging }, + { 'tree-node--drop-target': isDropTarget && canDrop(component) } + ) + + return ( +
handleDragStart(component)} + onDragOver={(e) => handleDragOver(e, component)} + onDrop={() => handleDrop(component)} + > + {/* Recursive rendering */} + {hasChildren && isExpanded && ( +
+ {component.children.map(child => + renderNode(child, depth + 1) + )} +
+ )} +
+ ) + } + + return
{components.map(c => renderNode(c, 0))}
+} +``` + +**Why React?** Recursion, dynamic styling, drag-and-drop state, event coordination. JSON can't express recursive algorithms. + +### 5. Third-Party Integrations +Libraries with imperative APIs need wrapper components: + +```tsx +// ❌ Cannot be JSON +import MonacoEditor from '@monaco-editor/react' + +export function LazyMonacoEditor({ value, onChange, language }: EditorProps) { + const editorRef = useRef() + const [isValid, setIsValid] = useState(true) + + useEffect(() => { + // Configure Monaco + monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ + target: monaco.languages.typescript.ScriptTarget.ES2020, + allowNonTsExtensions: true, + moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs, + }) + + // Add custom validation + monaco.editor.onDidChangeMarkers(([uri]) => { + const markers = monaco.editor.getModelMarkers({ resource: uri }) + setIsValid(markers.filter(m => m.severity === 8).length === 0) + }) + }, []) + + return ( + { + editorRef.current = editor + editor.addAction({ + id: 'format-document', + label: 'Format Document', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS], + run: () => editor.getAction('editor.action.formatDocument')?.run() + }) + }} + /> + ) +} +``` + +**Why React?** Third-party libraries expect imperative APIs (refs, lifecycle methods). JSON can reference the wrapper, but can't create it. + +## The Hybrid Pattern + +### JSON References React Components + +JSON schemas can reference any React component via the component registry: + +```json +{ + "id": "code-editor-section", + "type": "div", + "children": [ + { + "id": "monaco-editor", + "type": "LazyMonacoEditor", + "props": { + "language": "typescript", + "theme": "vs-dark" + } + } + ] +} +``` + +The `LazyMonacoEditor` is a React component with hooks, refs, and complex logic. JSON just *configures* it. + +### Component Registry: The Bridge + +```tsx +// src/lib/json-ui/component-registry.ts +export const componentRegistry: ComponentRegistry = { + // Simple components (could be JSON, but registered for convenience) + 'Button': Button, + 'Card': Card, + 'Input': Input, + + // Complex components (MUST be React) + 'LazyMonacoEditor': LazyMonacoEditor, + 'DataSourceManager': DataSourceManager, + 'ComponentTree': ComponentTree, + 'SchemaEditor': SchemaEditor, + + // Hook-based components + 'ProjectDashboard': ProjectDashboard, // uses multiple hooks + 'CodeEditor': CodeEditor, // uses useEffect, useRef + 'JSONModelDesigner': JSONModelDesigner, // uses custom hooks +} +``` + +### The 68 React Components + +These aren't legacy cruft - they're **essential implementation**: + +| Component Type | Count | Why React? | +|----------------|-------|------------| +| Hook-based managers | 15 | useState, useEffect, useCallback | +| Event-heavy UIs | 12 | Complex event handlers, drag-and-drop | +| Third-party wrappers | 8 | Monaco, Chart.js, D3 integrations | +| Recursive renderers | 6 | Tree views, nested structures | +| Complex forms | 10 | Validation, multi-step flows | +| Dialog/Modal managers | 8 | Portal rendering, focus management | +| Real-time features | 5 | WebSocket, polling, live updates | +| Lazy loaders | 4 | Code splitting, dynamic imports | + +## When to Use What + +### Use JSON When: +✅ Composing existing components +✅ Configuring layouts and styling +✅ Defining data sources and bindings +✅ Simple linear action chains +✅ Static page structure +✅ Theming and branding +✅ Feature flags and toggles + +### Use React When: +✅ Complex state management (hooks) +✅ Imperative APIs (refs, third-party libs) +✅ Advanced event handling (validation, async) +✅ Recursive algorithms +✅ Performance optimization (memo, virtualization) +✅ Type-safe business logic (classes, interfaces) +✅ Side effects and lifecycle management + +## Real-World Example: Data Source Manager + +### What's in JSON +```json +{ + "id": "data-source-section", + "type": "Card", + "children": [ + { + "type": "CardHeader", + "children": [ + { "type": "CardTitle", "children": "Data Sources" } + ] + }, + { + "type": "CardContent", + "children": [ + { + "id": "ds-manager", + "type": "DataSourceManager", + "dataBinding": { + "dataSources": { "source": "pageSources" } + }, + "events": [{ + "event": "onChange", + "actions": [ + { "type": "setState", "target": "pageSources", "valueFrom": "event" } + ] + }] + } + ] + } + ] +} +``` + +**JSON handles:** Layout, composition, data binding, simple state updates + +### What's in React +```tsx +// src/components/organisms/DataSourceManager.tsx +export function DataSourceManager({ dataSources, onChange }: Props) { + // ✅ Hook for complex state management + const { + dataSources: localSources, + addDataSource, + updateDataSource, + deleteDataSource, + getDependents, // ← Complex computed logic + } = useDataSourceManager(dataSources) + + // ✅ Local UI state + const [editingSource, setEditingSource] = useState(null) + const [dialogOpen, setDialogOpen] = useState(false) + + // ✅ Complex event handler with validation + const handleDeleteSource = (id: string) => { + const dependents = getDependents(id) + if (dependents.length > 0) { + toast.error(`Cannot delete: ${dependents.length} sources depend on it`) + return + } + deleteDataSource(id) + onChange(localSources.filter(ds => ds.id !== id)) + toast.success('Data source deleted') + } + + // ✅ Conditional rendering based on complex state + const groupedSources = useMemo(() => ({ + kv: localSources.filter(ds => ds.type === 'kv'), + computed: localSources.filter(ds => ds.type === 'computed'), + static: localSources.filter(ds => ds.type === 'static'), + }), [localSources]) + + return ( +
+ {localSources.length === 0 ? ( + + ) : ( + + + + + + )} + +
+ ) +} +``` + +**React handles:** Hooks, validation, dependency checking, grouping logic, dialog state + +## The Power of Hybrid + +### Flexibility +- **JSON**: Quick changes, visual editing, non-developer friendly +- **React**: Full programming power when needed + +### Composition +- **JSON**: Compose pages from molecules and organisms +- **React**: Implement the organisms with complex logic + +### Evolution +- **Start Simple**: Build in JSON, reference simple React components +- **Add Complexity**: When logic grows, extract to custom React component +- **Stay Declarative**: JSON schema stays clean, complexity hidden in components + +### Example Evolution + +**Day 1 - Pure JSON:** +```json +{ + "type": "Button", + "events": [{ "event": "onClick", "actions": [{ "type": "toast" }] }] +} +``` + +**Day 30 - Need validation:** +```json +{ + "type": "ValidatedButton", // ← Custom React component + "props": { "validationRules": ["required", "email"] } +} +``` + +```tsx +// Custom component when JSON isn't enough +function ValidatedButton({ validationRules, onClick, ...props }) { + const validate = useValidation(validationRules) + + const handleClick = () => { + if (!validate()) { + toast.error('Validation failed') + return + } + onClick?.() + } + + return