mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
Merge pull request #16 from johndoe6345789/copilot/fix-skipping-components
Scan actual component files to generate complete registry (219 vs 60 components)
This commit is contained in:
152
JSON_COMPATIBILITY_ANALYSIS.md
Normal file
152
JSON_COMPATIBILITY_ANALYSIS.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# JSON-Powered Components Analysis
|
||||
|
||||
This document identifies which molecules and organisms can be powered by the JSON UI system.
|
||||
|
||||
## Summary
|
||||
|
||||
- **Total Components**: 219 (117 atoms, 41 molecules, 15 organisms, 46 ui)
|
||||
- **Fully JSON-Compatible**: 14 (molecules: 13, organisms: 1)
|
||||
- **Maybe JSON-Compatible**: 41 (molecules: 27, organisms: 14)
|
||||
- **Not Compatible**: 1 (molecules: 1)
|
||||
|
||||
## 🔥 Fully JSON-Compatible Components
|
||||
|
||||
These components have simple, serializable props and no complex state/logic. They can be directly rendered from JSON.
|
||||
|
||||
### Molecules (13)
|
||||
- **AppBranding** - Title and subtitle branding
|
||||
- **Breadcrumb** - Navigation breadcrumb trail
|
||||
- **EmptyEditorState** - Empty state for editor
|
||||
- **LabelWithBadge** - Label with badge indicator
|
||||
- **LazyBarChart** - Bar chart visualization
|
||||
- **LazyD3BarChart** - D3-based bar chart
|
||||
- **LazyLineChart** - Line chart visualization
|
||||
- **LoadingFallback** - Loading message display
|
||||
- **LoadingState** - Loading state indicator
|
||||
- **NavigationGroupHeader** - Navigation section header
|
||||
- **SaveIndicator** - Last saved indicator
|
||||
- **SeedDataManager** - Seed data management
|
||||
- **StorageSettings** - Storage configuration
|
||||
|
||||
### Organisms (1)
|
||||
- **PageHeader** - Page header component
|
||||
|
||||
## ⚠️ Maybe JSON-Compatible Components
|
||||
|
||||
These components have callbacks/event handlers but could work with JSON UI if we implement an event binding system.
|
||||
|
||||
### Molecules (27)
|
||||
#### Interactive Components (Need event binding)
|
||||
- **ActionBar** - Action button toolbar
|
||||
- **DataCard** - Custom data display card
|
||||
- **EditorActions** - Editor action buttons
|
||||
- **EditorToolbar** - Editor toolbar
|
||||
- **SearchBar** - Search bar with input
|
||||
- **SearchInput** - Search input with icon
|
||||
- **StatCard** - Statistic card display
|
||||
- **ToolbarButton** - Toolbar button component
|
||||
- **NavigationItem** - Navigation menu item
|
||||
|
||||
#### Components with State (Need state binding)
|
||||
- **BindingEditor** - Data binding editor
|
||||
- **ComponentBindingDialog** - Component binding dialog
|
||||
- **ComponentPalette** - Component palette selector
|
||||
- **ComponentTree** - Component tree view
|
||||
- **DataSourceEditorDialog** - Data source editor
|
||||
- **FileTabs** - File tabs navigation
|
||||
- **PropertyEditor** - Property editor panel
|
||||
- **TreeFormDialog** - Tree form dialog
|
||||
- **TreeListHeader** - Tree list header
|
||||
|
||||
#### Display/Layout Components
|
||||
- **CanvasRenderer** - Canvas rendering component
|
||||
- **CodeExplanationDialog** - Code explanation dialog
|
||||
- **DataSourceCard** - Data source card
|
||||
- **EmptyState** - Empty state display
|
||||
- **LazyInlineMonacoEditor** - Inline Monaco editor
|
||||
- **LazyMonacoEditor** - Monaco code editor
|
||||
- **MonacoEditorPanel** - Monaco editor panel
|
||||
- **PageHeaderContent** - Page header content
|
||||
- **TreeCard** - Tree card component
|
||||
|
||||
### Organisms (14)
|
||||
All organisms have complex interactions and state management:
|
||||
- **AppHeader** - Application header
|
||||
- **DataSourceManager** - Data source management panel
|
||||
- **EmptyCanvasState** - Empty canvas state display
|
||||
- **JSONUIShowcase** - JSON UI showcase component
|
||||
- **NavigationMenu** - Navigation menu system
|
||||
- **SchemaCodeViewer** - Schema code viewer
|
||||
- **SchemaEditorCanvas** - Schema editor canvas
|
||||
- **SchemaEditorLayout** - Schema editor layout
|
||||
- **SchemaEditorPropertiesPanel** - Properties panel
|
||||
- **SchemaEditorSidebar** - Editor sidebar
|
||||
- **SchemaEditorStatusBar** - Editor status bar
|
||||
- **SchemaEditorToolbar** - Editor toolbar
|
||||
- **ToolbarActions** - Toolbar action buttons
|
||||
- **TreeListPanel** - Tree list panel
|
||||
|
||||
## ❌ Not JSON-Compatible
|
||||
|
||||
### Molecules (1)
|
||||
- **GitHubBuildStatus** - Makes API calls, has complex async logic
|
||||
|
||||
## Recommendations
|
||||
|
||||
### For Fully Compatible Components
|
||||
These can be added to the JSON component registry immediately:
|
||||
```typescript
|
||||
// Add to src/lib/json-ui/component-registry.tsx
|
||||
import { AppBranding } from '@/components/molecules/AppBranding'
|
||||
import { LabelWithBadge } from '@/components/molecules/LabelWithBadge'
|
||||
// ... etc
|
||||
```
|
||||
|
||||
### For Maybe Compatible Components
|
||||
To make these JSON-compatible, implement:
|
||||
|
||||
1. **Event Binding System** - Map string event names to actions
|
||||
```json
|
||||
{
|
||||
"type": "SearchInput",
|
||||
"events": {
|
||||
"onChange": { "action": "updateSearch", "target": "searchQuery" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **State Binding System** - Bind component state to data sources
|
||||
```json
|
||||
{
|
||||
"type": "ComponentTree",
|
||||
"bindings": {
|
||||
"items": { "source": "treeData" },
|
||||
"selectedId": { "source": "selectedNode" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Complex Component Wrappers** - Create JSON-friendly wrapper components
|
||||
```typescript
|
||||
// Wrap complex components with simplified JSON interfaces
|
||||
export function JSONFriendlyDataSourceManager(props: SerializableProps) {
|
||||
// Convert JSON props to complex component props
|
||||
return <DataSourceManager {...convertProps(props)} />
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# List all components with JSON compatibility
|
||||
npm run components:list
|
||||
|
||||
# Regenerate the registry from source files
|
||||
npm run components:scan
|
||||
```
|
||||
|
||||
## See Also
|
||||
- `json-components-registry.json` - Full component registry
|
||||
- `scripts/list-json-components.cjs` - Component listing script
|
||||
- `scripts/scan-and-update-registry.cjs` - Registry generator
|
||||
- `src/lib/json-ui/component-registry.tsx` - JSON UI component registry
|
||||
106
SOLUTION_SUMMARY.md
Normal file
106
SOLUTION_SUMMARY.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Solution Summary: Fixed Component Registry
|
||||
|
||||
## Problem
|
||||
The `list-json-components.cjs` script was showing only 60 components out of 200+ components in the codebase, appearing to "skip most components."
|
||||
|
||||
## Root Cause
|
||||
The script was reading from a static `json-components-registry.json` file that was manually maintained and only included 60 hardcoded components. The actual codebase has 219 components across atoms, molecules, organisms, and UI libraries.
|
||||
|
||||
## Solution
|
||||
|
||||
### 1. Created Dynamic Registry Scanner (`scan-and-update-registry.cjs`)
|
||||
- Scans actual component files in `src/components/`
|
||||
- Discovers all atoms (117), molecules (41), organisms (15), and ui (46) components
|
||||
- Analyzes JSON compatibility for molecules and organisms
|
||||
- Generates updated `json-components-registry.json` with all 219 components
|
||||
|
||||
### 2. Enhanced List Script (`list-json-components.cjs`)
|
||||
- Shows component source (atoms/molecules/organisms/ui)
|
||||
- Displays JSON compatibility status:
|
||||
- 🔥 Fully JSON-compatible
|
||||
- ⚠️ Maybe JSON-compatible (needs event binding)
|
||||
- ✅ Supported (ready to use)
|
||||
- 📋 Planned (future additions)
|
||||
|
||||
### 3. Added NPM Script
|
||||
```bash
|
||||
npm run components:scan # Regenerate registry from source files
|
||||
npm run components:list # List all components with details
|
||||
```
|
||||
|
||||
## Results
|
||||
|
||||
### Before
|
||||
```
|
||||
Total: 60 components
|
||||
- 46 supported
|
||||
- 14 planned
|
||||
- Missing 159 components!
|
||||
```
|
||||
|
||||
### After
|
||||
```
|
||||
Total: 219 components (+159 discovered!)
|
||||
|
||||
By Source:
|
||||
- 🧱 117 Atoms (foundation)
|
||||
- 🧪 41 Molecules (composite)
|
||||
- 🦠 15 Organisms (complex)
|
||||
- 🎨 46 UI (shadcn/ui)
|
||||
|
||||
JSON Compatibility:
|
||||
- 🔥 14 Fully compatible (simple props)
|
||||
- ⚠️ 41 Maybe compatible (need event binding)
|
||||
- ✅ 150 Supported (atoms + ui)
|
||||
- 📋 14 Planned (future)
|
||||
```
|
||||
|
||||
## Key Insights
|
||||
|
||||
### Atoms are the Foundation ✅
|
||||
All 117 atoms are ready to use as building blocks for JSON-powered UIs.
|
||||
|
||||
### Molecules Analysis
|
||||
- **13 fully JSON-compatible**: Simple props, no complex state
|
||||
- AppBranding, Breadcrumb, LazyBarChart, LoadingState, etc.
|
||||
- **27 maybe compatible**: Have callbacks, need event binding system
|
||||
- ActionBar, DataCard, SearchInput, StatCard, etc.
|
||||
- **1 not compatible**: GitHubBuildStatus (API calls)
|
||||
|
||||
### Organisms Analysis
|
||||
- **1 fully JSON-compatible**: PageHeader
|
||||
- **14 maybe compatible**: Complex components that need state/event binding
|
||||
- AppHeader, NavigationMenu, SchemaEditor components, etc.
|
||||
|
||||
## Documentation
|
||||
- `JSON_COMPATIBILITY_ANALYSIS.md` - Detailed analysis of which molecules/organisms can be JSON-powered
|
||||
- `json-components-registry.json` - Complete registry with 219 components
|
||||
- `scripts/scan-and-update-registry.cjs` - Registry generator script
|
||||
- `scripts/list-json-components.cjs` - Enhanced listing script
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# List all components
|
||||
npm run components:list
|
||||
|
||||
# Regenerate registry after adding new components
|
||||
npm run components:scan
|
||||
|
||||
# Filter by status
|
||||
npm run components:list -- --status=json-compatible
|
||||
npm run components:list -- --status=maybe-json-compatible
|
||||
|
||||
# Get JSON output
|
||||
npm run components:list -- --format=json
|
||||
```
|
||||
|
||||
## Next Steps (Optional)
|
||||
|
||||
To make the 41 "maybe compatible" components fully JSON-powered:
|
||||
|
||||
1. **Implement Event Binding System** - Map string event names to actions
|
||||
2. **Implement State Binding System** - Bind component state to data sources
|
||||
3. **Create Wrapper Components** - Wrap complex components with JSON-friendly interfaces
|
||||
|
||||
See `JSON_COMPATIBILITY_ANALYSIS.md` for detailed recommendations.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,8 @@
|
||||
"pages:list": "node scripts/list-pages.js",
|
||||
"pages:validate": "tsx src/config/validate-config.ts",
|
||||
"pages:generate": "node scripts/generate-page.js",
|
||||
"components:list": "node scripts/list-json-components.cjs"
|
||||
"components:list": "node scripts/list-json-components.cjs",
|
||||
"components:scan": "node scripts/scan-and-update-registry.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.2.0",
|
||||
|
||||
@@ -73,15 +73,21 @@ categories.forEach(category => {
|
||||
|
||||
categoryComps.forEach(comp => {
|
||||
const children = comp.canHaveChildren ? '👶 Can have children' : '➖ No children'
|
||||
const statusIcon = comp.status === 'supported' ? '✅' : '📋'
|
||||
const subComps = comp.subComponents ? ` (includes: ${comp.subComponents.join(', ')})` : ''
|
||||
let statusIcon = comp.status === 'supported' ? '✅' : '📋'
|
||||
if (comp.status === 'json-compatible') statusIcon = '🔥'
|
||||
if (comp.status === 'maybe-json-compatible') statusIcon = '⚠️ '
|
||||
|
||||
console.log(` ${statusIcon} ${comp.name} (${comp.type})`)
|
||||
const source = comp.source ? ` [${comp.source}]` : ''
|
||||
|
||||
console.log(` ${statusIcon} ${comp.name} (${comp.type})${source}`)
|
||||
console.log(` ${comp.description}`)
|
||||
console.log(` ${children}`)
|
||||
if (comp.subComponents) {
|
||||
console.log(` Sub-components: ${comp.subComponents.join(', ')}`)
|
||||
}
|
||||
if (comp.jsonCompatible !== undefined && !comp.jsonCompatible) {
|
||||
console.log(` ⚠️ Not JSON-powered (${comp.jsonReason || 'complex state/logic'})`)
|
||||
}
|
||||
console.log('')
|
||||
})
|
||||
})
|
||||
@@ -92,9 +98,24 @@ console.log(`\nTotal Components: ${componentsList.length}`)
|
||||
if (statusFilter === 'all') {
|
||||
const supported = componentsList.filter(c => c.status === 'supported').length
|
||||
const planned = componentsList.filter(c => c.status === 'planned').length
|
||||
const jsonCompatible = componentsList.filter(c => c.status === 'json-compatible').length
|
||||
const maybeCompatible = componentsList.filter(c => c.status === 'maybe-json-compatible').length
|
||||
const atoms = componentsList.filter(c => c.source === 'atoms').length
|
||||
const molecules = componentsList.filter(c => c.source === 'molecules').length
|
||||
const organisms = componentsList.filter(c => c.source === 'organisms').length
|
||||
const ui = componentsList.filter(c => c.source === 'ui').length
|
||||
|
||||
console.log(`\nBy Status:`)
|
||||
console.log(` ✅ Supported: ${supported}`)
|
||||
console.log(` 🔥 JSON-Compatible: ${jsonCompatible}`)
|
||||
console.log(` ⚠️ Maybe JSON-Compatible: ${maybeCompatible}`)
|
||||
console.log(` 📋 Planned: ${planned}`)
|
||||
|
||||
console.log(`\nBy Source:`)
|
||||
if (atoms > 0) console.log(` 🧱 Atoms: ${atoms}`)
|
||||
if (molecules > 0) console.log(` 🧪 Molecules: ${molecules}`)
|
||||
if (organisms > 0) console.log(` 🦠 Organisms: ${organisms}`)
|
||||
if (ui > 0) console.log(` 🎨 UI: ${ui}`)
|
||||
}
|
||||
|
||||
console.log(`\nBy Category:`)
|
||||
|
||||
368
scripts/scan-and-update-registry.cjs
Normal file
368
scripts/scan-and-update-registry.cjs
Normal file
@@ -0,0 +1,368 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Scan and Update JSON Components Registry
|
||||
*
|
||||
* Scans the actual component files in src/components and updates
|
||||
* json-components-registry.json to include all real components.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/scan-and-update-registry.cjs
|
||||
*/
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
// Scan a directory for .tsx files
|
||||
function scanComponents(dir) {
|
||||
const files = fs.readdirSync(dir)
|
||||
return files
|
||||
.filter(f => f.endsWith('.tsx') && !f.startsWith('index'))
|
||||
.map(f => f.replace('.tsx', ''))
|
||||
}
|
||||
|
||||
// Get all components
|
||||
const atomsPath = path.join(process.cwd(), 'src/components/atoms')
|
||||
const moleculesPath = path.join(process.cwd(), 'src/components/molecules')
|
||||
const organismsPath = path.join(process.cwd(), 'src/components/organisms')
|
||||
const uiPath = path.join(process.cwd(), 'src/components/ui')
|
||||
|
||||
const atoms = scanComponents(atomsPath)
|
||||
const molecules = scanComponents(moleculesPath)
|
||||
const organisms = fs.existsSync(organismsPath) ? scanComponents(organismsPath) : []
|
||||
const ui = scanComponents(uiPath)
|
||||
|
||||
console.log(`Found ${atoms.length} atoms, ${molecules.length} molecules, ${organisms.length} organisms, ${ui.length} ui components`)
|
||||
console.log(`Total: ${atoms.length + molecules.length + organisms.length + ui.length} components`)
|
||||
|
||||
// Read existing registry to preserve metadata
|
||||
const registryPath = path.join(process.cwd(), 'json-components-registry.json')
|
||||
let existingRegistry = { components: [] }
|
||||
if (fs.existsSync(registryPath)) {
|
||||
existingRegistry = JSON.parse(fs.readFileSync(registryPath, 'utf8'))
|
||||
}
|
||||
|
||||
// Create a map of existing components for quick lookup
|
||||
const existingMap = new Map()
|
||||
existingRegistry.components.forEach(c => {
|
||||
existingMap.set(c.type, c)
|
||||
})
|
||||
|
||||
// Category mapping heuristics
|
||||
function guessCategory(name) {
|
||||
const lower = name.toLowerCase()
|
||||
|
||||
// Layout
|
||||
if (lower.includes('container') || lower.includes('grid') || lower.includes('flex') ||
|
||||
lower.includes('stack') || lower.includes('card') || lower.includes('section') ||
|
||||
lower.includes('drawer') || lower.includes('modal') || lower.includes('dialog')) {
|
||||
return 'layout'
|
||||
}
|
||||
|
||||
// Input
|
||||
if (lower.includes('input') || lower.includes('button') || lower.includes('select') ||
|
||||
lower.includes('checkbox') || lower.includes('radio') || lower.includes('switch') ||
|
||||
lower.includes('slider') || lower.includes('form') || lower.includes('upload') ||
|
||||
lower.includes('picker') || lower.includes('toggle')) {
|
||||
return 'input'
|
||||
}
|
||||
|
||||
// Navigation
|
||||
if (lower.includes('link') || lower.includes('breadcrumb') || lower.includes('tab') ||
|
||||
lower.includes('menu') || lower.includes('navigation')) {
|
||||
return 'navigation'
|
||||
}
|
||||
|
||||
// Feedback
|
||||
if (lower.includes('alert') || lower.includes('notification') || lower.includes('badge') ||
|
||||
lower.includes('status') || lower.includes('error') || lower.includes('empty') ||
|
||||
lower.includes('loading') || lower.includes('spinner') || lower.includes('toast')) {
|
||||
return 'feedback'
|
||||
}
|
||||
|
||||
// Data
|
||||
if (lower.includes('table') || lower.includes('list') || lower.includes('data') ||
|
||||
lower.includes('metric') || lower.includes('stat') || lower.includes('chart') ||
|
||||
lower.includes('timeline') || lower.includes('keyvalue')) {
|
||||
return 'data'
|
||||
}
|
||||
|
||||
// Display (default for text, images, icons, etc.)
|
||||
if (lower.includes('text') || lower.includes('heading') || lower.includes('label') ||
|
||||
lower.includes('image') || lower.includes('avatar') || lower.includes('icon') ||
|
||||
lower.includes('code') || lower.includes('tag') || lower.includes('skeleton') ||
|
||||
lower.includes('separator') || lower.includes('divider') || lower.includes('progress')) {
|
||||
return 'display'
|
||||
}
|
||||
|
||||
return 'custom'
|
||||
}
|
||||
|
||||
function canHaveChildren(name) {
|
||||
const noChildren = [
|
||||
'Input', 'TextArea', 'Select', 'Checkbox', 'Radio', 'Switch', 'Slider', 'NumberInput',
|
||||
'Image', 'Avatar', 'Separator', 'Divider', 'Progress', 'ProgressBar', 'Skeleton',
|
||||
'Spinner', 'Icon', 'FileUpload', 'DatePicker', 'CircularProgress', 'StatusIcon',
|
||||
'StatusBadge', 'ErrorBadge', 'Table', 'DataTable', 'List', 'DataList', 'KeyValue',
|
||||
'StatCard', 'MetricCard', 'DataCard', 'SearchInput', 'ActionBar', 'Timeline'
|
||||
]
|
||||
return !noChildren.includes(name)
|
||||
}
|
||||
|
||||
function getDescription(name) {
|
||||
// Try to generate a reasonable description
|
||||
const descriptions = {
|
||||
// Common patterns
|
||||
'Accordion': 'Collapsible content sections',
|
||||
'ActionButton': 'Button with action icon',
|
||||
'ActionBar': 'Action button toolbar',
|
||||
'Alert': 'Alert notification message',
|
||||
'Avatar': 'User avatar image',
|
||||
'AvatarGroup': 'Group of user avatars',
|
||||
'Badge': 'Small status or count indicator',
|
||||
'Breadcrumb': 'Navigation breadcrumb trail',
|
||||
'Button': 'Interactive button element',
|
||||
'ButtonGroup': 'Group of related buttons',
|
||||
'Calendar': 'Calendar date selector',
|
||||
'Card': 'Container card component',
|
||||
'Checkbox': 'Checkbox toggle control',
|
||||
'Chip': 'Compact element for tags or selections',
|
||||
'CircularProgress': 'Circular progress indicator',
|
||||
'Code': 'Inline or block code display',
|
||||
'CommandPalette': 'Command search and execution',
|
||||
'Container': 'Generic container element',
|
||||
'ContextMenu': 'Right-click context menu',
|
||||
'DataCard': 'Custom data display card',
|
||||
'DataList': 'Styled data list',
|
||||
'DataTable': 'Advanced data table with sorting and filtering',
|
||||
'DatePicker': 'Date selection input',
|
||||
'Divider': 'Visual section divider',
|
||||
'Drawer': 'Sliding panel overlay',
|
||||
'EmptyState': 'Empty state placeholder',
|
||||
'ErrorBadge': 'Error state badge',
|
||||
'FileUpload': 'File upload control',
|
||||
'Flex': 'Flexible box layout container',
|
||||
'Form': 'Form container component',
|
||||
'Grid': 'Responsive grid layout',
|
||||
'Heading': 'Heading text with level (h1-h6)',
|
||||
'HoverCard': 'Card shown on hover',
|
||||
'Icon': 'Icon from icon library',
|
||||
'IconButton': 'Button with icon only',
|
||||
'Image': 'Image element with loading states',
|
||||
'InfoBox': 'Information box with icon',
|
||||
'Input': 'Text input field',
|
||||
'Kbd': 'Keyboard key display',
|
||||
'KeyValue': 'Key-value pair display',
|
||||
'Label': 'Form label element',
|
||||
'Link': 'Hyperlink element',
|
||||
'List': 'Generic list renderer with custom items',
|
||||
'Menu': 'Menu component',
|
||||
'MetricCard': 'Metric display card',
|
||||
'Modal': 'Modal dialog overlay',
|
||||
'Notification': 'Toast notification',
|
||||
'NumberInput': 'Numeric input with increment/decrement',
|
||||
'PasswordInput': 'Password input with visibility toggle',
|
||||
'Popover': 'Popover overlay content',
|
||||
'Progress': 'Progress bar indicator',
|
||||
'ProgressBar': 'Linear progress bar',
|
||||
'Radio': 'Radio button selection',
|
||||
'Rating': 'Star rating component',
|
||||
'ScrollArea': 'Scrollable container area',
|
||||
'SearchInput': 'Search input with icon',
|
||||
'Select': 'Dropdown select control',
|
||||
'Separator': 'Visual divider line',
|
||||
'Skeleton': 'Loading skeleton placeholder',
|
||||
'Slider': 'Numeric range slider',
|
||||
'Spinner': 'Loading spinner',
|
||||
'Stack': 'Vertical or horizontal stack layout',
|
||||
'StatCard': 'Statistic card display',
|
||||
'StatusBadge': 'Status indicator badge',
|
||||
'StatusIcon': 'Status indicator icon',
|
||||
'Stepper': 'Step-by-step navigation',
|
||||
'Switch': 'Toggle switch control',
|
||||
'Table': 'Data table',
|
||||
'Tabs': 'Tabbed interface container',
|
||||
'Tag': 'Removable tag or chip',
|
||||
'Text': 'Text content with typography variants',
|
||||
'TextArea': 'Multi-line text input',
|
||||
'Timeline': 'Timeline visualization',
|
||||
'Toggle': 'Toggle button control',
|
||||
'Tooltip': 'Tooltip overlay text'
|
||||
}
|
||||
|
||||
return descriptions[name] || `${name} component`
|
||||
}
|
||||
|
||||
// JSON compatibility lists based on analysis
|
||||
const jsonCompatibleMolecules = [
|
||||
'AppBranding', 'Breadcrumb', 'EmptyEditorState', 'LabelWithBadge',
|
||||
'LazyBarChart', 'LazyD3BarChart', 'LazyLineChart', 'LoadingFallback',
|
||||
'LoadingState', 'NavigationGroupHeader', 'SaveIndicator',
|
||||
'SeedDataManager', 'StorageSettings'
|
||||
]
|
||||
|
||||
const maybeJsonCompatibleMolecules = [
|
||||
'ActionBar', 'BindingEditor', 'CanvasRenderer', 'CodeExplanationDialog',
|
||||
'ComponentBindingDialog', 'ComponentPalette', 'ComponentTree', 'DataCard',
|
||||
'DataSourceCard', 'DataSourceEditorDialog', 'EditorActions', 'EditorToolbar',
|
||||
'EmptyState', 'FileTabs', 'LazyInlineMonacoEditor', 'LazyMonacoEditor',
|
||||
'MonacoEditorPanel', 'NavigationItem', 'PageHeaderContent', 'PropertyEditor',
|
||||
'SearchBar', 'SearchInput', 'StatCard', 'ToolbarButton', 'TreeCard',
|
||||
'TreeFormDialog', 'TreeListHeader'
|
||||
]
|
||||
|
||||
const jsonCompatibleOrganisms = ['PageHeader']
|
||||
|
||||
const maybeJsonCompatibleOrganisms = [
|
||||
'AppHeader', 'DataSourceManager', 'EmptyCanvasState', 'JSONUIShowcase',
|
||||
'NavigationMenu', 'SchemaCodeViewer', 'SchemaEditorCanvas',
|
||||
'SchemaEditorLayout', 'SchemaEditorPropertiesPanel', 'SchemaEditorSidebar',
|
||||
'SchemaEditorStatusBar', 'SchemaEditorToolbar', 'ToolbarActions', 'TreeListPanel'
|
||||
]
|
||||
|
||||
// Build components array
|
||||
const components = []
|
||||
|
||||
// Process atoms (all are foundational, mark as supported)
|
||||
atoms.forEach(name => {
|
||||
const existing = existingMap.get(name)
|
||||
components.push({
|
||||
type: name,
|
||||
name: existing?.name || name,
|
||||
category: existing?.category || guessCategory(name),
|
||||
canHaveChildren: existing?.canHaveChildren !== undefined ? existing.canHaveChildren : canHaveChildren(name),
|
||||
description: existing?.description || getDescription(name),
|
||||
status: existing?.status || 'supported',
|
||||
source: 'atoms'
|
||||
})
|
||||
})
|
||||
|
||||
// Process molecules with JSON compatibility marking
|
||||
molecules.forEach(name => {
|
||||
const existing = existingMap.get(name)
|
||||
let status = existing?.status || 'supported'
|
||||
|
||||
if (jsonCompatibleMolecules.includes(name)) {
|
||||
status = 'json-compatible'
|
||||
} else if (maybeJsonCompatibleMolecules.includes(name)) {
|
||||
status = 'maybe-json-compatible'
|
||||
}
|
||||
|
||||
components.push({
|
||||
type: name,
|
||||
name: existing?.name || name,
|
||||
category: existing?.category || guessCategory(name),
|
||||
canHaveChildren: existing?.canHaveChildren !== undefined ? existing.canHaveChildren : canHaveChildren(name),
|
||||
description: existing?.description || getDescription(name),
|
||||
status,
|
||||
source: 'molecules',
|
||||
jsonCompatible: jsonCompatibleMolecules.includes(name) || maybeJsonCompatibleMolecules.includes(name)
|
||||
})
|
||||
})
|
||||
|
||||
// Process organisms with JSON compatibility marking
|
||||
organisms.forEach(name => {
|
||||
const existing = existingMap.get(name)
|
||||
let status = existing?.status || 'supported'
|
||||
|
||||
if (jsonCompatibleOrganisms.includes(name)) {
|
||||
status = 'json-compatible'
|
||||
} else if (maybeJsonCompatibleOrganisms.includes(name)) {
|
||||
status = 'maybe-json-compatible'
|
||||
}
|
||||
|
||||
components.push({
|
||||
type: name,
|
||||
name: existing?.name || name,
|
||||
category: existing?.category || guessCategory(name),
|
||||
canHaveChildren: existing?.canHaveChildren !== undefined ? existing.canHaveChildren : true,
|
||||
description: existing?.description || `${name} organism component`,
|
||||
status,
|
||||
source: 'organisms',
|
||||
jsonCompatible: jsonCompatibleOrganisms.includes(name) || maybeJsonCompatibleOrganisms.includes(name)
|
||||
})
|
||||
})
|
||||
|
||||
// Process ui components (convert kebab-case to PascalCase)
|
||||
ui.forEach(name => {
|
||||
// Convert kebab-case to PascalCase
|
||||
const pascalName = name.split('-').map(word =>
|
||||
word.charAt(0).toUpperCase() + word.slice(1)
|
||||
).join('')
|
||||
|
||||
const existing = existingMap.get(pascalName) || existingMap.get(name)
|
||||
components.push({
|
||||
type: pascalName,
|
||||
name: existing?.name || pascalName,
|
||||
category: existing?.category || guessCategory(pascalName),
|
||||
canHaveChildren: existing?.canHaveChildren !== undefined ? existing.canHaveChildren : canHaveChildren(pascalName),
|
||||
description: existing?.description || getDescription(pascalName),
|
||||
status: existing?.status || 'supported',
|
||||
source: 'ui'
|
||||
})
|
||||
})
|
||||
|
||||
// Sort by category then name
|
||||
components.sort((a, b) => {
|
||||
if (a.category !== b.category) {
|
||||
const order = ['layout', 'input', 'display', 'navigation', 'feedback', 'data', 'custom']
|
||||
return order.indexOf(a.category) - order.indexOf(b.category)
|
||||
}
|
||||
return a.name.localeCompare(b.name)
|
||||
})
|
||||
|
||||
// Count by category
|
||||
const byCategory = {}
|
||||
components.forEach(c => {
|
||||
byCategory[c.category] = (byCategory[c.category] || 0) + 1
|
||||
})
|
||||
|
||||
// Build the registry
|
||||
const registry = {
|
||||
$schema: './schemas/json-components-registry-schema.json',
|
||||
version: '2.0.0',
|
||||
description: 'Registry of all components in the application',
|
||||
lastUpdated: new Date().toISOString(),
|
||||
categories: {
|
||||
layout: 'Layout and container components',
|
||||
input: 'Form inputs and interactive controls',
|
||||
display: 'Display and presentation components',
|
||||
navigation: 'Navigation and routing components',
|
||||
feedback: 'Alerts, notifications, and status indicators',
|
||||
data: 'Data display and visualization components',
|
||||
custom: 'Custom domain-specific components'
|
||||
},
|
||||
components,
|
||||
statistics: {
|
||||
total: components.length,
|
||||
supported: components.filter(c => c.status === 'supported').length,
|
||||
planned: components.filter(c => c.status === 'planned').length,
|
||||
jsonCompatible: components.filter(c => c.status === 'json-compatible').length,
|
||||
maybeJsonCompatible: components.filter(c => c.status === 'maybe-json-compatible').length,
|
||||
byCategory,
|
||||
bySource: {
|
||||
atoms: atoms.length,
|
||||
molecules: molecules.length,
|
||||
organisms: organisms.length,
|
||||
ui: ui.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write to file
|
||||
fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2) + '\n', 'utf8')
|
||||
|
||||
console.log('\n✅ Updated json-components-registry.json')
|
||||
console.log(` Total components: ${registry.statistics.total}`)
|
||||
console.log(` By source:`)
|
||||
console.log(` 🧱 atoms: ${registry.statistics.bySource.atoms}`)
|
||||
console.log(` 🧪 molecules: ${registry.statistics.bySource.molecules}`)
|
||||
console.log(` 🦠 organisms: ${registry.statistics.bySource.organisms}`)
|
||||
console.log(` 🎨 ui: ${registry.statistics.bySource.ui}`)
|
||||
console.log(` JSON compatibility:`)
|
||||
console.log(` 🔥 Fully compatible: ${registry.statistics.jsonCompatible}`)
|
||||
console.log(` ⚠️ Maybe compatible: ${registry.statistics.maybeJsonCompatible}`)
|
||||
console.log(` By category:`)
|
||||
Object.entries(byCategory).forEach(([cat, count]) => {
|
||||
console.log(` ${cat}: ${count}`)
|
||||
})
|
||||
Reference in New Issue
Block a user