Merge pull request #15 from johndoe6345789/copilot/list-json-components

[WIP] Add list of components that can be JSON
This commit is contained in:
2026-01-17 21:58:12 +00:00
committed by GitHub
8 changed files with 1553 additions and 9 deletions

192
JSON_COMPONENTS.md Normal file
View File

@@ -0,0 +1,192 @@
# JSON UI Components Registry
This document describes the JSON UI component system and lists all components that can be rendered from JSON schemas.
## Overview
The JSON UI system allows you to define user interfaces using JSON schemas instead of writing React code. This is useful for:
- Dynamic UI generation
- No-code/low-code interfaces
- Configuration-driven UIs
- Rapid prototyping
## Quick Start
### List All JSON-Compatible Components
```bash
# List all components with details
npm run components:list
# List only supported components
npm run components:list -- --status=supported
# List only planned components
npm run components:list -- --status=planned
# Output as JSON
npm run components:list -- --format=json
```
### Using JSON UI Components
Components are defined in the `ComponentType` union in `src/types/json-ui.ts` and registered in `src/lib/json-ui/component-registry.tsx`.
Example JSON schema:
```json
{
"id": "example-page",
"type": "Card",
"props": {
"className": "p-6"
},
"children": [
{
"id": "heading",
"type": "Heading",
"props": {
"level": 2,
"children": "Welcome"
}
},
{
"id": "description",
"type": "Text",
"props": {
"children": "This is a dynamically rendered component"
}
},
{
"id": "cta",
"type": "Button",
"props": {
"variant": "default",
"children": "Get Started"
}
}
]
}
```
## Component Categories
### Layout Components (12)
Container elements for organizing content:
- `div`, `section`, `article`, `header`, `footer`, `main` - HTML semantic elements
- `Card` - Container with optional header, content, and footer
- `Grid` - Responsive grid layout
- `Stack` - Vertical or horizontal stack layout
- `Flex` - Flexible box layout
- `Container` - Centered container with max-width
- `Dialog` - Modal dialog overlay
### Input Components (11)
Form inputs and interactive controls:
- `Button` - Interactive button
- `Input` - Text input field
- `TextArea` - Multi-line text input
- `Select` - Dropdown select
- `Checkbox` - Checkbox toggle
- `Radio` - Radio button
- `Switch` - Toggle switch
- `Slider` - Numeric range slider
- `NumberInput` - Numeric input with increment/decrement
- `DatePicker` - Date selection (planned)
- `FileUpload` - File upload control (planned)
### Display Components (16)
Presentation and visual elements:
- `Heading` - Heading text (h1-h6)
- `Text` - Text content with typography
- `Label` - Form label
- `Badge` - Status or count indicator
- `Tag` - Removable tag/chip
- `Code` - Inline or block code
- `Image` - Image with loading states
- `Avatar` - User avatar image
- `Icon` - Icon from library (planned)
- `Progress` - Progress bar
- `Spinner` - Loading spinner
- `Skeleton` - Loading placeholder
- `Separator` - Visual divider
- `CircularProgress` - Circular indicator (planned)
- `ProgressBar` - Linear progress (planned)
- `Divider` - Section divider (planned)
### Navigation Components (3)
Navigation and routing:
- `Link` - Hyperlink element
- `Breadcrumb` - Navigation trail (planned)
- `Tabs` - Tabbed interface
### Feedback Components (7)
Alerts, notifications, and status:
- `Alert` - Alert notification message
- `InfoBox` - Information box with icon
- `EmptyState` - Empty state placeholder
- `StatusBadge` - Status indicator
- `StatusIcon` - Status icon (planned)
- `ErrorBadge` - Error state (planned)
- `Notification` - Toast notification (planned)
### Data Components (8)
Data display and visualization:
- `List` - Generic list renderer
- `Table` - Data table
- `KeyValue` - Key-value pair display
- `StatCard` - Statistic card
- `DataList` - Styled data list (planned)
- `DataTable` - Advanced table with sorting/filtering (planned)
- `Timeline` - Timeline visualization (planned)
- `MetricCard` - Metric display (planned)
### Custom Components (3)
Domain-specific components:
- `DataCard` - Custom data display card
- `SearchInput` - Search input with icon
- `ActionBar` - Action button toolbar
## Current Status
- **Total Components**: 60
- **Supported**: 46 (77%)
- **Planned**: 14 (23%)
## Files
- `json-components-registry.json` - Complete registry with metadata
- `src/types/json-ui.ts` - TypeScript types and ComponentType union
- `src/lib/json-ui/component-registry.tsx` - Component registry mapping
- `src/lib/component-definitions.ts` - Component definitions with defaults
- `scripts/list-json-components.cjs` - CLI tool to list components
## Adding New Components
To add a new component to the JSON UI system:
1. Add the component type to `ComponentType` union in `src/types/json-ui.ts`
2. Import and register it in `src/lib/json-ui/component-registry.tsx`
3. Add component definition in `src/lib/component-definitions.ts`
4. Update `json-components-registry.json` with metadata
5. Test the component in a JSON schema
## Migration Strategy
Components marked as "planned" are:
- Available in the codebase as React components
- Not yet integrated into the JSON UI system
- Can be migrated following the steps above
Priority for migration:
1. High-usage components
2. Components with simple props
3. Components with good atomic design
4. Components without complex state management
## Related Documentation
- [PRD.md](./PRD.md) - Product requirements document
- [REDUX_DOCUMENTATION.md](./REDUX_DOCUMENTATION.md) - Redux integration
- [src/types/json-ui.ts](./src/types/json-ui.ts) - Type definitions
- [src/lib/component-definitions.ts](./src/lib/component-definitions.ts) - Component metadata

494
json-components-list.json Normal file
View File

@@ -0,0 +1,494 @@
[
{
"type": "div",
"name": "Container (div)",
"category": "layout",
"canHaveChildren": true,
"description": "Generic container element",
"status": "supported"
},
{
"type": "section",
"name": "Section",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic section element",
"status": "supported"
},
{
"type": "article",
"name": "Article",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic article element",
"status": "supported"
},
{
"type": "header",
"name": "Header",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic header element",
"status": "supported"
},
{
"type": "footer",
"name": "Footer",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic footer element",
"status": "supported"
},
{
"type": "main",
"name": "Main",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic main content element",
"status": "supported"
},
{
"type": "Card",
"name": "Card",
"category": "layout",
"canHaveChildren": true,
"description": "Container card with optional header, content, and footer",
"status": "supported",
"subComponents": [
"CardHeader",
"CardTitle",
"CardDescription",
"CardContent",
"CardFooter"
]
},
{
"type": "Grid",
"name": "Grid",
"category": "layout",
"canHaveChildren": true,
"description": "Responsive grid layout",
"status": "supported"
},
{
"type": "Flex",
"name": "Flex",
"category": "layout",
"canHaveChildren": true,
"description": "Flexible box layout container",
"status": "supported"
},
{
"type": "Stack",
"name": "Stack",
"category": "layout",
"canHaveChildren": true,
"description": "Vertical or horizontal stack layout",
"status": "supported"
},
{
"type": "Container",
"name": "Container",
"category": "layout",
"canHaveChildren": true,
"description": "Centered container with max-width",
"status": "supported"
},
{
"type": "Button",
"name": "Button",
"category": "input",
"canHaveChildren": true,
"description": "Interactive button element",
"status": "supported"
},
{
"type": "Input",
"name": "Input",
"category": "input",
"canHaveChildren": false,
"description": "Text input field",
"status": "supported"
},
{
"type": "TextArea",
"name": "TextArea",
"category": "input",
"canHaveChildren": false,
"description": "Multi-line text input",
"status": "supported"
},
{
"type": "Select",
"name": "Select",
"category": "input",
"canHaveChildren": false,
"description": "Dropdown select control",
"status": "supported"
},
{
"type": "Checkbox",
"name": "Checkbox",
"category": "input",
"canHaveChildren": false,
"description": "Checkbox toggle control",
"status": "supported"
},
{
"type": "Radio",
"name": "Radio",
"category": "input",
"canHaveChildren": false,
"description": "Radio button selection",
"status": "supported"
},
{
"type": "Switch",
"name": "Switch",
"category": "input",
"canHaveChildren": false,
"description": "Toggle switch control",
"status": "supported"
},
{
"type": "Slider",
"name": "Slider",
"category": "input",
"canHaveChildren": false,
"description": "Numeric range slider",
"status": "supported"
},
{
"type": "NumberInput",
"name": "NumberInput",
"category": "input",
"canHaveChildren": false,
"description": "Numeric input with increment/decrement",
"status": "supported"
},
{
"type": "DatePicker",
"name": "DatePicker",
"category": "input",
"canHaveChildren": false,
"description": "Date selection input",
"status": "planned"
},
{
"type": "FileUpload",
"name": "FileUpload",
"category": "input",
"canHaveChildren": false,
"description": "File upload control",
"status": "planned"
},
{
"type": "Text",
"name": "Text",
"category": "display",
"canHaveChildren": true,
"description": "Text content with typography variants",
"status": "supported"
},
{
"type": "Heading",
"name": "Heading",
"category": "display",
"canHaveChildren": true,
"description": "Heading text with level (h1-h6)",
"status": "supported"
},
{
"type": "Label",
"name": "Label",
"category": "display",
"canHaveChildren": true,
"description": "Form label element",
"status": "supported"
},
{
"type": "Badge",
"name": "Badge",
"category": "display",
"canHaveChildren": true,
"description": "Small status or count indicator",
"status": "supported"
},
{
"type": "Tag",
"name": "Tag",
"category": "display",
"canHaveChildren": true,
"description": "Removable tag or chip",
"status": "supported"
},
{
"type": "Code",
"name": "Code",
"category": "display",
"canHaveChildren": true,
"description": "Inline or block code display",
"status": "supported"
},
{
"type": "Image",
"name": "Image",
"category": "display",
"canHaveChildren": false,
"description": "Image element with loading states",
"status": "supported"
},
{
"type": "Avatar",
"name": "Avatar",
"category": "display",
"canHaveChildren": false,
"description": "User avatar image",
"status": "supported"
},
{
"type": "Icon",
"name": "Icon",
"category": "display",
"canHaveChildren": false,
"description": "Icon from icon library",
"status": "planned"
},
{
"type": "Separator",
"name": "Separator",
"category": "display",
"canHaveChildren": false,
"description": "Visual divider line",
"status": "supported"
},
{
"type": "Divider",
"name": "Divider",
"category": "display",
"canHaveChildren": false,
"description": "Visual section divider",
"status": "planned"
},
{
"type": "Progress",
"name": "Progress",
"category": "display",
"canHaveChildren": false,
"description": "Progress bar indicator",
"status": "supported"
},
{
"type": "ProgressBar",
"name": "ProgressBar",
"category": "display",
"canHaveChildren": false,
"description": "Linear progress bar",
"status": "planned"
},
{
"type": "CircularProgress",
"name": "CircularProgress",
"category": "display",
"canHaveChildren": false,
"description": "Circular progress indicator",
"status": "planned"
},
{
"type": "Spinner",
"name": "Spinner",
"category": "display",
"canHaveChildren": false,
"description": "Loading spinner",
"status": "supported"
},
{
"type": "Skeleton",
"name": "Skeleton",
"category": "display",
"canHaveChildren": false,
"description": "Loading skeleton placeholder",
"status": "supported"
},
{
"type": "Link",
"name": "Link",
"category": "navigation",
"canHaveChildren": true,
"description": "Hyperlink element",
"status": "supported"
},
{
"type": "Breadcrumb",
"name": "Breadcrumb",
"category": "navigation",
"canHaveChildren": false,
"description": "Navigation breadcrumb trail",
"status": "planned"
},
{
"type": "Tabs",
"name": "Tabs",
"category": "navigation",
"canHaveChildren": true,
"description": "Tabbed interface container",
"status": "supported",
"subComponents": [
"TabsList",
"TabsTrigger",
"TabsContent"
]
},
{
"type": "Alert",
"name": "Alert",
"category": "feedback",
"canHaveChildren": true,
"description": "Alert notification message",
"status": "supported"
},
{
"type": "InfoBox",
"name": "InfoBox",
"category": "feedback",
"canHaveChildren": true,
"description": "Information box with icon",
"status": "supported"
},
{
"type": "Notification",
"name": "Notification",
"category": "feedback",
"canHaveChildren": true,
"description": "Toast notification",
"status": "planned"
},
{
"type": "StatusBadge",
"name": "StatusBadge",
"category": "feedback",
"canHaveChildren": false,
"description": "Status indicator badge",
"status": "supported"
},
{
"type": "StatusIcon",
"name": "StatusIcon",
"category": "feedback",
"canHaveChildren": false,
"description": "Status indicator icon",
"status": "planned"
},
{
"type": "EmptyState",
"name": "EmptyState",
"category": "feedback",
"canHaveChildren": true,
"description": "Empty state placeholder",
"status": "supported"
},
{
"type": "ErrorBadge",
"name": "ErrorBadge",
"category": "feedback",
"canHaveChildren": false,
"description": "Error state badge",
"status": "planned"
},
{
"type": "List",
"name": "List",
"category": "data",
"canHaveChildren": false,
"description": "Generic list renderer with custom items",
"status": "supported"
},
{
"type": "DataList",
"name": "DataList",
"category": "data",
"canHaveChildren": false,
"description": "Styled data list",
"status": "planned"
},
{
"type": "Table",
"name": "Table",
"category": "data",
"canHaveChildren": false,
"description": "Data table",
"status": "supported"
},
{
"type": "DataTable",
"name": "DataTable",
"category": "data",
"canHaveChildren": false,
"description": "Advanced data table with sorting and filtering",
"status": "planned"
},
{
"type": "KeyValue",
"name": "KeyValue",
"category": "data",
"canHaveChildren": false,
"description": "Key-value pair display",
"status": "supported"
},
{
"type": "Timeline",
"name": "Timeline",
"category": "data",
"canHaveChildren": false,
"description": "Timeline visualization",
"status": "planned"
},
{
"type": "StatCard",
"name": "StatCard",
"category": "data",
"canHaveChildren": false,
"description": "Statistic card display",
"status": "supported"
},
{
"type": "MetricCard",
"name": "MetricCard",
"category": "data",
"canHaveChildren": false,
"description": "Metric display card",
"status": "planned"
},
{
"type": "DataCard",
"name": "DataCard",
"category": "custom",
"canHaveChildren": false,
"description": "Custom data display card",
"status": "supported"
},
{
"type": "SearchInput",
"name": "SearchInput",
"category": "custom",
"canHaveChildren": false,
"description": "Search input with icon",
"status": "supported"
},
{
"type": "ActionBar",
"name": "ActionBar",
"category": "custom",
"canHaveChildren": false,
"description": "Action button toolbar",
"status": "supported"
},
{
"type": "Dialog",
"name": "Dialog",
"category": "layout",
"canHaveChildren": true,
"description": "Modal dialog overlay",
"status": "supported"
}
]

View File

@@ -0,0 +1,512 @@
{
"$schema": "./schemas/json-components-registry-schema.json",
"version": "1.0.0",
"description": "Registry of all components that can be rendered from JSON schemas",
"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": [
{
"type": "div",
"name": "Container (div)",
"category": "layout",
"canHaveChildren": true,
"description": "Generic container element",
"status": "supported"
},
{
"type": "section",
"name": "Section",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic section element",
"status": "supported"
},
{
"type": "article",
"name": "Article",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic article element",
"status": "supported"
},
{
"type": "header",
"name": "Header",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic header element",
"status": "supported"
},
{
"type": "footer",
"name": "Footer",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic footer element",
"status": "supported"
},
{
"type": "main",
"name": "Main",
"category": "layout",
"canHaveChildren": true,
"description": "Semantic main content element",
"status": "supported"
},
{
"type": "Card",
"name": "Card",
"category": "layout",
"canHaveChildren": true,
"description": "Container card with optional header, content, and footer",
"status": "supported",
"subComponents": ["CardHeader", "CardTitle", "CardDescription", "CardContent", "CardFooter"]
},
{
"type": "Grid",
"name": "Grid",
"category": "layout",
"canHaveChildren": true,
"description": "Responsive grid layout",
"status": "supported"
},
{
"type": "Flex",
"name": "Flex",
"category": "layout",
"canHaveChildren": true,
"description": "Flexible box layout container",
"status": "supported"
},
{
"type": "Stack",
"name": "Stack",
"category": "layout",
"canHaveChildren": true,
"description": "Vertical or horizontal stack layout",
"status": "supported"
},
{
"type": "Container",
"name": "Container",
"category": "layout",
"canHaveChildren": true,
"description": "Centered container with max-width",
"status": "supported"
},
{
"type": "Button",
"name": "Button",
"category": "input",
"canHaveChildren": true,
"description": "Interactive button element",
"status": "supported"
},
{
"type": "Input",
"name": "Input",
"category": "input",
"canHaveChildren": false,
"description": "Text input field",
"status": "supported"
},
{
"type": "TextArea",
"name": "TextArea",
"category": "input",
"canHaveChildren": false,
"description": "Multi-line text input",
"status": "supported"
},
{
"type": "Select",
"name": "Select",
"category": "input",
"canHaveChildren": false,
"description": "Dropdown select control",
"status": "supported"
},
{
"type": "Checkbox",
"name": "Checkbox",
"category": "input",
"canHaveChildren": false,
"description": "Checkbox toggle control",
"status": "supported"
},
{
"type": "Radio",
"name": "Radio",
"category": "input",
"canHaveChildren": false,
"description": "Radio button selection",
"status": "supported"
},
{
"type": "Switch",
"name": "Switch",
"category": "input",
"canHaveChildren": false,
"description": "Toggle switch control",
"status": "supported"
},
{
"type": "Slider",
"name": "Slider",
"category": "input",
"canHaveChildren": false,
"description": "Numeric range slider",
"status": "supported"
},
{
"type": "NumberInput",
"name": "NumberInput",
"category": "input",
"canHaveChildren": false,
"description": "Numeric input with increment/decrement",
"status": "supported"
},
{
"type": "DatePicker",
"name": "DatePicker",
"category": "input",
"canHaveChildren": false,
"description": "Date selection input",
"status": "planned"
},
{
"type": "FileUpload",
"name": "FileUpload",
"category": "input",
"canHaveChildren": false,
"description": "File upload control",
"status": "planned"
},
{
"type": "Text",
"name": "Text",
"category": "display",
"canHaveChildren": true,
"description": "Text content with typography variants",
"status": "supported"
},
{
"type": "Heading",
"name": "Heading",
"category": "display",
"canHaveChildren": true,
"description": "Heading text with level (h1-h6)",
"status": "supported"
},
{
"type": "Label",
"name": "Label",
"category": "display",
"canHaveChildren": true,
"description": "Form label element",
"status": "supported"
},
{
"type": "Badge",
"name": "Badge",
"category": "display",
"canHaveChildren": true,
"description": "Small status or count indicator",
"status": "supported"
},
{
"type": "Tag",
"name": "Tag",
"category": "display",
"canHaveChildren": true,
"description": "Removable tag or chip",
"status": "supported"
},
{
"type": "Code",
"name": "Code",
"category": "display",
"canHaveChildren": true,
"description": "Inline or block code display",
"status": "supported"
},
{
"type": "Image",
"name": "Image",
"category": "display",
"canHaveChildren": false,
"description": "Image element with loading states",
"status": "supported"
},
{
"type": "Avatar",
"name": "Avatar",
"category": "display",
"canHaveChildren": false,
"description": "User avatar image",
"status": "supported"
},
{
"type": "Icon",
"name": "Icon",
"category": "display",
"canHaveChildren": false,
"description": "Icon from icon library",
"status": "planned"
},
{
"type": "Separator",
"name": "Separator",
"category": "display",
"canHaveChildren": false,
"description": "Visual divider line",
"status": "supported"
},
{
"type": "Divider",
"name": "Divider",
"category": "display",
"canHaveChildren": false,
"description": "Visual section divider",
"status": "planned"
},
{
"type": "Progress",
"name": "Progress",
"category": "display",
"canHaveChildren": false,
"description": "Progress bar indicator",
"status": "supported"
},
{
"type": "ProgressBar",
"name": "ProgressBar",
"category": "display",
"canHaveChildren": false,
"description": "Linear progress bar",
"status": "planned"
},
{
"type": "CircularProgress",
"name": "CircularProgress",
"category": "display",
"canHaveChildren": false,
"description": "Circular progress indicator",
"status": "planned"
},
{
"type": "Spinner",
"name": "Spinner",
"category": "display",
"canHaveChildren": false,
"description": "Loading spinner",
"status": "supported"
},
{
"type": "Skeleton",
"name": "Skeleton",
"category": "display",
"canHaveChildren": false,
"description": "Loading skeleton placeholder",
"status": "supported"
},
{
"type": "Link",
"name": "Link",
"category": "navigation",
"canHaveChildren": true,
"description": "Hyperlink element",
"status": "supported"
},
{
"type": "Breadcrumb",
"name": "Breadcrumb",
"category": "navigation",
"canHaveChildren": false,
"description": "Navigation breadcrumb trail",
"status": "planned"
},
{
"type": "Tabs",
"name": "Tabs",
"category": "navigation",
"canHaveChildren": true,
"description": "Tabbed interface container",
"status": "supported",
"subComponents": ["TabsList", "TabsTrigger", "TabsContent"]
},
{
"type": "Alert",
"name": "Alert",
"category": "feedback",
"canHaveChildren": true,
"description": "Alert notification message",
"status": "supported"
},
{
"type": "InfoBox",
"name": "InfoBox",
"category": "feedback",
"canHaveChildren": true,
"description": "Information box with icon",
"status": "supported"
},
{
"type": "Notification",
"name": "Notification",
"category": "feedback",
"canHaveChildren": true,
"description": "Toast notification",
"status": "planned"
},
{
"type": "StatusBadge",
"name": "StatusBadge",
"category": "feedback",
"canHaveChildren": false,
"description": "Status indicator badge",
"status": "supported"
},
{
"type": "StatusIcon",
"name": "StatusIcon",
"category": "feedback",
"canHaveChildren": false,
"description": "Status indicator icon",
"status": "planned"
},
{
"type": "EmptyState",
"name": "EmptyState",
"category": "feedback",
"canHaveChildren": true,
"description": "Empty state placeholder",
"status": "supported"
},
{
"type": "ErrorBadge",
"name": "ErrorBadge",
"category": "feedback",
"canHaveChildren": false,
"description": "Error state badge",
"status": "planned"
},
{
"type": "List",
"name": "List",
"category": "data",
"canHaveChildren": false,
"description": "Generic list renderer with custom items",
"status": "supported"
},
{
"type": "DataList",
"name": "DataList",
"category": "data",
"canHaveChildren": false,
"description": "Styled data list",
"status": "planned"
},
{
"type": "Table",
"name": "Table",
"category": "data",
"canHaveChildren": false,
"description": "Data table",
"status": "supported"
},
{
"type": "DataTable",
"name": "DataTable",
"category": "data",
"canHaveChildren": false,
"description": "Advanced data table with sorting and filtering",
"status": "planned"
},
{
"type": "KeyValue",
"name": "KeyValue",
"category": "data",
"canHaveChildren": false,
"description": "Key-value pair display",
"status": "supported"
},
{
"type": "Timeline",
"name": "Timeline",
"category": "data",
"canHaveChildren": false,
"description": "Timeline visualization",
"status": "planned"
},
{
"type": "StatCard",
"name": "StatCard",
"category": "data",
"canHaveChildren": false,
"description": "Statistic card display",
"status": "supported"
},
{
"type": "MetricCard",
"name": "MetricCard",
"category": "data",
"canHaveChildren": false,
"description": "Metric display card",
"status": "planned"
},
{
"type": "DataCard",
"name": "DataCard",
"category": "custom",
"canHaveChildren": false,
"description": "Custom data display card",
"status": "supported"
},
{
"type": "SearchInput",
"name": "SearchInput",
"category": "custom",
"canHaveChildren": false,
"description": "Search input with icon",
"status": "supported"
},
{
"type": "ActionBar",
"name": "ActionBar",
"category": "custom",
"canHaveChildren": false,
"description": "Action button toolbar",
"status": "supported"
},
{
"type": "Dialog",
"name": "Dialog",
"category": "layout",
"canHaveChildren": true,
"description": "Modal dialog overlay",
"status": "supported"
}
],
"statistics": {
"total": 60,
"supported": 46,
"planned": 14,
"byCategory": {
"layout": 12,
"input": 11,
"display": 16,
"navigation": 3,
"feedback": 7,
"data": 8,
"custom": 3
}
}
}

View File

@@ -20,7 +20,8 @@
"test:e2e:report": "playwright show-report",
"pages:list": "node scripts/list-pages.js",
"pages:validate": "tsx src/config/validate-config.ts",
"pages:generate": "node scripts/generate-page.js"
"pages:generate": "node scripts/generate-page.js",
"components:list": "node scripts/list-json-components.cjs"
},
"dependencies": {
"@heroicons/react": "^2.2.0",

118
scripts/list-json-components.cjs Executable file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env node
/**
* JSON Components List Script
*
* Lists all components that can be rendered from JSON using the JSON UI system.
*
* Usage:
* node scripts/list-json-components.cjs [--format=table|json] [--status=all|supported|planned]
*/
const fs = require('fs')
const path = require('path')
// Read the JSON components registry
const registryPath = path.join(process.cwd(), 'json-components-registry.json')
if (!fs.existsSync(registryPath)) {
console.error('❌ Could not find json-components-registry.json')
process.exit(1)
}
let registry
try {
registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'))
} catch (e) {
console.error('❌ Failed to parse json-components-registry.json:', e.message)
process.exit(1)
}
const format = process.argv.find(arg => arg.startsWith('--format='))?.split('=')[1] || 'table'
const statusFilter = process.argv.find(arg => arg.startsWith('--status='))?.split('=')[1] || 'all'
// Filter components by status if requested
let componentsList = registry.components
if (statusFilter !== 'all') {
componentsList = componentsList.filter(c => c.status === statusFilter)
}
if (format === 'json') {
console.log(JSON.stringify(componentsList, null, 2))
process.exit(0)
}
// Table format output
console.log('\n🧩 JSON-Compatible Components\n')
console.log('═══════════════════════════════════════════════════════════════════════════\n')
console.log(`These components can be rendered from JSON schemas using the JSON UI system.`)
if (statusFilter !== 'all') {
console.log(`\nFiltered by status: ${statusFilter}`)
}
console.log()
// Group by category
const categories = ['layout', 'input', 'display', 'navigation', 'feedback', 'data', 'custom']
const categoryIcons = {
layout: '📐',
input: '⌨️ ',
display: '🎨',
navigation: '🧭',
feedback: '💬',
data: '📊',
custom: '⚡'
}
categories.forEach(category => {
const categoryComps = componentsList.filter(c => c.category === category)
if (categoryComps.length === 0) return
console.log(`\n${categoryIcons[category]} ${category.toUpperCase()}\n`)
console.log('───────────────────────────────────────────────────────────────────────────')
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(', ')})` : ''
console.log(` ${statusIcon} ${comp.name} (${comp.type})`)
console.log(` ${comp.description}`)
console.log(` ${children}`)
if (comp.subComponents) {
console.log(` Sub-components: ${comp.subComponents.join(', ')}`)
}
console.log('')
})
})
console.log('═══════════════════════════════════════════════════════════════════════════')
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
console.log(`\nBy Status:`)
console.log(` ✅ Supported: ${supported}`)
console.log(` 📋 Planned: ${planned}`)
}
console.log(`\nBy Category:`)
categories.forEach(cat => {
const count = componentsList.filter(c => c.category === cat).length
if (count > 0) {
console.log(` ${categoryIcons[cat]} ${cat}: ${count}`)
}
})
console.log(`\nComponents with children support: ${componentsList.filter(c => c.canHaveChildren).length}`)
console.log('\n💡 Tips:')
console.log(' • Full registry in json-components-registry.json')
console.log(' • Component types defined in src/types/json-ui.ts')
console.log(' • Component registry in src/lib/json-ui/component-registry.tsx')
console.log(' • Component definitions in src/lib/component-definitions.ts')
console.log(' • Run with --format=json for JSON output')
console.log(' • Run with --status=supported to see only supported components')
console.log(' • Run with --status=planned to see only planned components')
console.log('')

View File

@@ -3,13 +3,14 @@ import { ComponentType } from '@/types/json-ui'
export interface ComponentDefinition {
type: ComponentType
label: string
category: 'layout' | 'input' | 'display' | 'custom'
category: 'layout' | 'input' | 'display' | 'navigation' | 'feedback' | 'data' | 'custom'
icon: string
defaultProps?: Record<string, any>
canHaveChildren?: boolean
}
export const componentDefinitions: ComponentDefinition[] = [
// Layout Components
{
type: 'div',
label: 'Container',
@@ -34,6 +35,30 @@ export const componentDefinitions: ComponentDefinition[] = [
canHaveChildren: true,
defaultProps: { columns: 2, gap: 4 }
},
{
type: 'Stack',
label: 'Stack',
category: 'layout',
icon: 'Stack',
canHaveChildren: true,
defaultProps: { direction: 'vertical', gap: 2 }
},
{
type: 'Flex',
label: 'Flex',
category: 'layout',
icon: 'ArrowsOutLineHorizontal',
canHaveChildren: true,
defaultProps: { direction: 'row', gap: 2 }
},
{
type: 'Container',
label: 'Container',
category: 'layout',
icon: 'Rectangle',
canHaveChildren: true,
defaultProps: { maxWidth: 'lg' }
},
{
type: 'Card',
label: 'Card',
@@ -42,11 +67,13 @@ export const componentDefinitions: ComponentDefinition[] = [
canHaveChildren: true,
defaultProps: { className: 'p-4' }
},
// Input Components
{
type: 'Button',
label: 'Button',
category: 'input',
icon: 'Circle',
canHaveChildren: true,
defaultProps: { children: 'Click me', variant: 'default' }
},
{
@@ -56,6 +83,13 @@ export const componentDefinitions: ComponentDefinition[] = [
icon: 'TextT',
defaultProps: { placeholder: 'Enter text...' }
},
{
type: 'TextArea',
label: 'TextArea',
category: 'input',
icon: 'TextAlignLeft',
defaultProps: { placeholder: 'Enter text...', rows: 4 }
},
{
type: 'Select',
label: 'Select',
@@ -70,6 +104,13 @@ export const componentDefinitions: ComponentDefinition[] = [
icon: 'CheckSquare',
defaultProps: {}
},
{
type: 'Radio',
label: 'Radio',
category: 'input',
icon: 'Circle',
defaultProps: {}
},
{
type: 'Switch',
label: 'Switch',
@@ -77,11 +118,27 @@ export const componentDefinitions: ComponentDefinition[] = [
icon: 'ToggleLeft',
defaultProps: {}
},
{
type: 'Slider',
label: 'Slider',
category: 'input',
icon: 'SlidersHorizontal',
defaultProps: { min: 0, max: 100, value: 50 }
},
{
type: 'NumberInput',
label: 'Number Input',
category: 'input',
icon: 'NumberCircleOne',
defaultProps: { placeholder: '0', min: 0 }
},
// Display Components
{
type: 'Heading',
label: 'Heading',
category: 'display',
icon: 'TextHOne',
canHaveChildren: true,
defaultProps: { level: 1, children: 'Heading' }
},
{
@@ -89,6 +146,7 @@ export const componentDefinitions: ComponentDefinition[] = [
label: 'Text',
category: 'display',
icon: 'Paragraph',
canHaveChildren: true,
defaultProps: { children: 'Text content' }
},
{
@@ -96,8 +154,39 @@ export const componentDefinitions: ComponentDefinition[] = [
label: 'Badge',
category: 'display',
icon: 'Tag',
canHaveChildren: true,
defaultProps: { children: 'Badge', variant: 'default' }
},
{
type: 'Tag',
label: 'Tag',
category: 'display',
icon: 'Tag',
canHaveChildren: true,
defaultProps: { children: 'Tag' }
},
{
type: 'Code',
label: 'Code',
category: 'display',
icon: 'Code',
canHaveChildren: true,
defaultProps: { children: 'code' }
},
{
type: 'Image',
label: 'Image',
category: 'display',
icon: 'Image',
defaultProps: { src: '', alt: 'Image' }
},
{
type: 'Avatar',
label: 'Avatar',
category: 'display',
icon: 'UserCircle',
defaultProps: { src: '', alt: 'Avatar' }
},
{
type: 'Progress',
label: 'Progress',
@@ -105,6 +194,20 @@ export const componentDefinitions: ComponentDefinition[] = [
icon: 'CircleNotch',
defaultProps: { value: 50 }
},
{
type: 'Spinner',
label: 'Spinner',
category: 'display',
icon: 'CircleNotch',
defaultProps: { size: 'md' }
},
{
type: 'Skeleton',
label: 'Skeleton',
category: 'display',
icon: 'Rectangle',
defaultProps: { className: 'h-4 w-full' }
},
{
type: 'Separator',
label: 'Separator',
@@ -112,6 +215,77 @@ export const componentDefinitions: ComponentDefinition[] = [
icon: 'Minus',
defaultProps: {}
},
// Navigation Components
{
type: 'Link',
label: 'Link',
category: 'navigation',
icon: 'Link',
canHaveChildren: true,
defaultProps: { href: '#', children: 'Link' }
},
// Feedback Components
{
type: 'Alert',
label: 'Alert',
category: 'feedback',
icon: 'Info',
canHaveChildren: true,
defaultProps: { variant: 'info', children: 'Alert message' }
},
{
type: 'InfoBox',
label: 'Info Box',
category: 'feedback',
icon: 'Info',
canHaveChildren: true,
defaultProps: { type: 'info', children: 'Information' }
},
{
type: 'EmptyState',
label: 'Empty State',
category: 'feedback',
icon: 'FolderOpen',
canHaveChildren: true,
defaultProps: { message: 'No items found' }
},
{
type: 'StatusBadge',
label: 'Status Badge',
category: 'feedback',
icon: 'Circle',
defaultProps: { status: 'active', children: 'Active' }
},
// Data Components
{
type: 'List',
label: 'List',
category: 'data',
icon: 'List',
defaultProps: { items: [], emptyMessage: 'No items' }
},
{
type: 'Table',
label: 'Table',
category: 'data',
icon: 'Table',
defaultProps: { data: [], columns: [] }
},
{
type: 'KeyValue',
label: 'Key Value',
category: 'data',
icon: 'Equals',
defaultProps: { label: 'Key', value: 'Value' }
},
{
type: 'StatCard',
label: 'Stat Card',
category: 'data',
icon: 'ChartBar',
defaultProps: { title: 'Metric', value: '0' }
},
// Custom Components
{
type: 'DataCard',
label: 'Data Card',
@@ -127,11 +301,12 @@ export const componentDefinitions: ComponentDefinition[] = [
defaultProps: { placeholder: 'Search...' }
},
{
type: 'StatusBadge',
label: 'Status Badge',
type: 'ActionBar',
label: 'Action Bar',
category: 'custom',
icon: 'Circle',
defaultProps: { status: 'active', children: 'Active' }
icon: 'Toolbox',
canHaveChildren: true,
defaultProps: { actions: [] }
},
]

View File

@@ -12,8 +12,28 @@ import { Separator } from '@/components/ui/separator'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { Heading } from '@/components/atoms/Heading'
import { Text } from '@/components/atoms/Text'
import { TextArea } from '@/components/atoms/TextArea'
import { List } from '@/components/atoms/List'
import { Grid } from '@/components/atoms/Grid'
import { Stack } from '@/components/atoms/Stack'
import { Flex } from '@/components/atoms/Flex'
import { Container } from '@/components/atoms/Container'
import { Link } from '@/components/atoms/Link'
import { Image } from '@/components/atoms/Image'
import { Avatar } from '@/components/atoms/Avatar'
import { Code } from '@/components/atoms/Code'
import { Tag } from '@/components/atoms/Tag'
import { Spinner } from '@/components/atoms/Spinner'
import { Skeleton } from '@/components/atoms/Skeleton'
import { Slider } from '@/components/atoms/Slider'
import { NumberInput } from '@/components/atoms/NumberInput'
import { Radio } from '@/components/atoms/Radio'
import { Alert } from '@/components/atoms/Alert'
import { InfoBox } from '@/components/atoms/InfoBox'
import { EmptyState } from '@/components/atoms/EmptyState'
import { Table } from '@/components/atoms/Table'
import { KeyValue } from '@/components/atoms/KeyValue'
import { StatCard } from '@/components/atoms/StatCard'
import { StatusBadge } from '@/components/atoms/StatusBadge'
import { DataCard } from '@/components/molecules/DataCard'
import { SearchInput } from '@/components/molecules/SearchInput'
@@ -29,10 +49,15 @@ export const componentRegistry: Record<ComponentType, any> = {
'Button': Button,
'Card': Card,
'Input': Input,
'TextArea': TextArea,
'Select': Select,
'Checkbox': Checkbox,
'Radio': Radio,
'Switch': Switch,
'Slider': Slider,
'NumberInput': NumberInput,
'Badge': Badge,
'Tag': Tag,
'Progress': Progress,
'Separator': Separator,
'Tabs': Tabs,
@@ -40,8 +65,27 @@ export const componentRegistry: Record<ComponentType, any> = {
'Text': Text,
'Heading': Heading,
'Label': Label,
'Link': Link,
'Image': Image,
'Avatar': Avatar,
'Code': Code,
'Spinner': Spinner,
'Skeleton': Skeleton,
'List': List,
'Grid': Grid,
'Stack': Stack,
'Flex': Flex,
'Container': Container,
'Alert': Alert,
'InfoBox': InfoBox,
'EmptyState': EmptyState,
'StatusBadge': StatusBadge,
'Table': Table,
'KeyValue': KeyValue,
'StatCard': StatCard,
'DataCard': DataCard,
'SearchInput': SearchInput,
'ActionBar': ActionBar,
}
export const cardSubComponents = {
@@ -63,6 +107,12 @@ export const customComponents = {
'DataCard': DataCard,
'SearchInput': SearchInput,
'ActionBar': ActionBar,
'StatCard': StatCard,
'KeyValue': KeyValue,
'Table': Table,
'Alert': Alert,
'InfoBox': InfoBox,
'EmptyState': EmptyState,
}
export function getComponent(type: ComponentType | string): any {

View File

@@ -3,10 +3,12 @@ import { ReactNode } from 'react'
export type ComponentType =
| 'div' | 'section' | 'article' | 'header' | 'footer' | 'main'
| 'Button' | 'Card' | 'CardHeader' | 'CardTitle' | 'CardDescription' | 'CardContent' | 'CardFooter'
| 'Input' | 'Select' | 'Checkbox' | 'Switch'
| 'Input' | 'TextArea' | 'Select' | 'Checkbox' | 'Radio' | 'Switch' | 'Slider' | 'NumberInput'
| 'Badge' | 'Progress' | 'Separator' | 'Tabs' | 'Dialog'
| 'Text' | 'Heading' | 'Label' | 'List' | 'Grid'
| 'StatusBadge' | 'DataCard' | 'SearchInput' | 'ActionBar'
| 'Text' | 'Heading' | 'Label' | 'List' | 'Grid' | 'Stack' | 'Flex' | 'Container'
| 'Link' | 'Image' | 'Avatar' | 'Code' | 'Tag' | 'Spinner' | 'Skeleton'
| 'Alert' | 'InfoBox' | 'EmptyState' | 'StatusBadge'
| 'Table' | 'KeyValue' | 'StatCard' | 'DataCard' | 'SearchInput' | 'ActionBar'
export type ActionType =
| 'create' | 'update' | 'delete' | 'navigate'