mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
Merge branch 'main' into codex/implement-prop-compatibility-for-components
This commit is contained in:
95
docs/JSON_COMPONENT_CONVERSION_TASKS.md
Normal file
95
docs/JSON_COMPONENT_CONVERSION_TASKS.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# JSON Component Conversion Tasks
|
||||
|
||||
This task list captures the next steps for expanding JSON UI coverage, split between **component migrations** and **framework enablers**.
|
||||
|
||||
## Component Migration Tasks (Planned → Supported)
|
||||
|
||||
### Input Components
|
||||
- [ ] **DatePicker**
|
||||
- Add `DatePicker` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `DatePicker` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
- [ ] **FileUpload**
|
||||
- Add `FileUpload` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `FileUpload` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
|
||||
### Display Components
|
||||
- [ ] **CircularProgress**
|
||||
- Add `CircularProgress` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `CircularProgress` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
- [ ] **Divider**
|
||||
- Add `Divider` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `Divider` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
- [ ] **ProgressBar**
|
||||
- Add `ProgressBar` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `ProgressBar` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
|
||||
### Navigation Components
|
||||
- [ ] **Breadcrumb**
|
||||
- Decide whether JSON should map to `BreadcrumbNav` (atoms) or `Breadcrumb` (molecules).
|
||||
- Align props and bindings to a single JSON-friendly surface.
|
||||
- Register a single `Breadcrumb` entry and set status to `supported` in `json-components-registry.json`.
|
||||
|
||||
### Feedback Components
|
||||
- [ ] **ErrorBadge**
|
||||
- Add `ErrorBadge` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `ErrorBadge` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
- [ ] **Notification**
|
||||
- Add `Notification` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `Notification` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
- [ ] **StatusIcon**
|
||||
- Add `StatusIcon` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `StatusIcon` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
|
||||
### Data Components
|
||||
- [ ] **DataList**
|
||||
- Add `DataList` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `DataList` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
- [ ] **DataTable**
|
||||
- Add `DataTable` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `DataTable` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
- [ ] **MetricCard**
|
||||
- Add `MetricCard` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `MetricCard` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
- [ ] **Timeline**
|
||||
- Add `Timeline` to `ComponentType` in `src/types/json-ui.ts`.
|
||||
- Register `Timeline` in `src/lib/json-ui/component-registry.tsx`.
|
||||
- Add metadata/defaults to `src/lib/component-definitions.ts`.
|
||||
- Flip status to `supported` in `json-components-registry.json`.
|
||||
|
||||
## Framework Enablers
|
||||
|
||||
- [ ] **Event binding extensions**
|
||||
- Expand event/action coverage to support richer interactions via JSON expressions.
|
||||
- Confirm compatibility with existing `expression` and `valueTemplate` handling.
|
||||
- [ ] **State binding system**
|
||||
- Add support for stateful bindings needed by interactive components.
|
||||
- Document and enforce which components require state binding.
|
||||
- [ ] **JSON-friendly wrappers**
|
||||
- Create wrapper components for hook-heavy/side-effect components.
|
||||
- Register wrappers in the JSON registry instead of direct usage.
|
||||
- [ ] **Registry normalization**
|
||||
- Resolve duplicate component entries (e.g., multiple `Breadcrumb` variants) in `json-components-registry.json`.
|
||||
- [ ] **Showcase schema coverage**
|
||||
- Add JSON schema examples for each newly supported component to keep demos current.
|
||||
@@ -1219,7 +1219,7 @@
|
||||
"category": "data",
|
||||
"canHaveChildren": false,
|
||||
"description": "Styled data list",
|
||||
"status": "planned",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
},
|
||||
{
|
||||
@@ -1238,7 +1238,7 @@
|
||||
"category": "data",
|
||||
"canHaveChildren": false,
|
||||
"description": "Advanced data table with sorting and filtering",
|
||||
"status": "planned",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
},
|
||||
{
|
||||
@@ -1304,7 +1304,7 @@
|
||||
"category": "data",
|
||||
"canHaveChildren": false,
|
||||
"description": "Metric display card",
|
||||
"status": "planned",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
},
|
||||
{
|
||||
@@ -1369,7 +1369,7 @@
|
||||
"category": "data",
|
||||
"canHaveChildren": false,
|
||||
"description": "Timeline visualization",
|
||||
"status": "planned",
|
||||
"status": "supported",
|
||||
"source": "atoms"
|
||||
},
|
||||
{
|
||||
@@ -2043,8 +2043,8 @@
|
||||
],
|
||||
"statistics": {
|
||||
"total": 219,
|
||||
"supported": 150,
|
||||
"planned": 14,
|
||||
"supported": 154,
|
||||
"planned": 10,
|
||||
"jsonCompatible": 14,
|
||||
"maybeJsonCompatible": 41,
|
||||
"byCategory": {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { AtomicComponentDemo } from '@/components/AtomicComponentDemo'
|
||||
import { DashboardDemoPage } from '@/components/DashboardDemoPage'
|
||||
import { PageRenderer } from '@/lib/json-ui/page-renderer'
|
||||
import { hydrateSchema } from '@/schemas/schema-loader'
|
||||
import { feedbackAtomsDemoSchema } from '@/schemas/page-schemas'
|
||||
import { dataComponentsDemoSchema } from '@/schemas/page-schemas'
|
||||
import todoListJson from '@/schemas/todo-list.json'
|
||||
import newMoleculesShowcaseJson from '@/schemas/new-molecules-showcase.json'
|
||||
|
||||
@@ -27,6 +27,7 @@ export function JSONUIShowcasePage() {
|
||||
<TabsTrigger value="atomic">Atomic Components</TabsTrigger>
|
||||
<TabsTrigger value="feedback">Feedback Atoms</TabsTrigger>
|
||||
<TabsTrigger value="molecules">New Molecules</TabsTrigger>
|
||||
<TabsTrigger value="data-components">Data Components</TabsTrigger>
|
||||
<TabsTrigger value="dashboard">JSON Dashboard</TabsTrigger>
|
||||
<TabsTrigger value="todos">JSON Todo List</TabsTrigger>
|
||||
</TabsList>
|
||||
@@ -44,6 +45,10 @@ export function JSONUIShowcasePage() {
|
||||
<TabsContent value="molecules" className="h-full m-0 data-[state=active]:block">
|
||||
<PageRenderer schema={newMoleculesShowcaseSchema} />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="data-components" className="h-full m-0 data-[state=active]:block">
|
||||
<PageRenderer schema={dataComponentsDemoSchema} />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="dashboard" className="h-full m-0 data-[state=active]:block">
|
||||
<DashboardDemoPage />
|
||||
|
||||
@@ -3,10 +3,11 @@ import { cn } from '@/lib/utils'
|
||||
|
||||
export interface DataListProps {
|
||||
items: any[]
|
||||
renderItem: (item: any, index: number) => ReactNode
|
||||
renderItem?: (item: any, index: number) => ReactNode
|
||||
emptyMessage?: string
|
||||
className?: string
|
||||
itemClassName?: string
|
||||
itemKey?: string
|
||||
}
|
||||
|
||||
export function DataList({
|
||||
@@ -15,6 +16,7 @@ export function DataList({
|
||||
emptyMessage = 'No items',
|
||||
className,
|
||||
itemClassName,
|
||||
itemKey,
|
||||
}: DataListProps) {
|
||||
if (items.length === 0) {
|
||||
return (
|
||||
@@ -24,11 +26,28 @@ export function DataList({
|
||||
)
|
||||
}
|
||||
|
||||
const renderFallbackItem = (item: any) => {
|
||||
if (itemKey && item && typeof item === 'object') {
|
||||
const value = item[itemKey]
|
||||
if (value !== undefined && value !== null) {
|
||||
return typeof value === 'string' || typeof value === 'number'
|
||||
? value
|
||||
: JSON.stringify(value)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof item === 'string' || typeof item === 'number') {
|
||||
return item
|
||||
}
|
||||
|
||||
return JSON.stringify(item)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn('space-y-2', className)}>
|
||||
{items.map((item, index) => (
|
||||
<div key={index} className={cn('transition-colors', itemClassName)}>
|
||||
{renderItem(item, index)}
|
||||
{renderItem ? renderItem(item, index) : renderFallbackItem(item)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -382,6 +382,17 @@ export const componentDefinitions: ComponentDefinition[] = [
|
||||
icon: 'List',
|
||||
defaultProps: { items: [], emptyMessage: 'No items' }
|
||||
},
|
||||
{
|
||||
type: 'DataList',
|
||||
label: 'Data List',
|
||||
category: 'data',
|
||||
icon: 'List',
|
||||
defaultProps: {
|
||||
items: ['Daily summary', 'New signups', 'Pending approvals'],
|
||||
emptyMessage: 'No updates',
|
||||
itemClassName: 'rounded-md border border-border bg-card/50 px-4 py-2'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'Table',
|
||||
label: 'Table',
|
||||
@@ -389,6 +400,25 @@ export const componentDefinitions: ComponentDefinition[] = [
|
||||
icon: 'Table',
|
||||
defaultProps: { data: [], columns: [] }
|
||||
},
|
||||
{
|
||||
type: 'DataTable',
|
||||
label: 'Data Table',
|
||||
category: 'data',
|
||||
icon: 'Table',
|
||||
defaultProps: {
|
||||
columns: [
|
||||
{ key: 'name', header: 'Name' },
|
||||
{ key: 'status', header: 'Status' },
|
||||
{ key: 'owner', header: 'Owner' },
|
||||
],
|
||||
data: [
|
||||
{ name: 'Launch Plan', status: 'In Progress', owner: 'Avery' },
|
||||
{ name: 'Design Review', status: 'Scheduled', owner: 'Jordan' },
|
||||
{ name: 'QA Checklist', status: 'Done', owner: 'Riley' },
|
||||
],
|
||||
emptyMessage: 'No records available',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'KeyValue',
|
||||
label: 'Key Value',
|
||||
@@ -403,6 +433,45 @@ export const componentDefinitions: ComponentDefinition[] = [
|
||||
icon: 'ChartBar',
|
||||
defaultProps: { title: 'Metric', value: '0' }
|
||||
},
|
||||
{
|
||||
type: 'MetricCard',
|
||||
label: 'Metric Card',
|
||||
category: 'data',
|
||||
icon: 'ChartBar',
|
||||
defaultProps: {
|
||||
label: 'Active Users',
|
||||
value: '1,248',
|
||||
trend: { value: 12.4, direction: 'up' },
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'Timeline',
|
||||
label: 'Timeline',
|
||||
category: 'data',
|
||||
icon: 'Clock',
|
||||
defaultProps: {
|
||||
items: [
|
||||
{
|
||||
title: 'Planning',
|
||||
description: 'Finalize milestones',
|
||||
timestamp: 'Mon 9:00 AM',
|
||||
status: 'completed',
|
||||
},
|
||||
{
|
||||
title: 'Execution',
|
||||
description: 'Kick off delivery',
|
||||
timestamp: 'Tue 11:00 AM',
|
||||
status: 'current',
|
||||
},
|
||||
{
|
||||
title: 'Review',
|
||||
description: 'Collect feedback',
|
||||
timestamp: 'Wed 3:00 PM',
|
||||
status: 'pending',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
// Custom Components
|
||||
{
|
||||
type: 'DataCard',
|
||||
|
||||
@@ -136,10 +136,16 @@ export const shadcnComponents: UIComponentRegistry = {
|
||||
AvatarImage,
|
||||
}
|
||||
|
||||
export const atomComponents: UIComponentRegistry = buildRegistryFromNames(
|
||||
atomRegistryNames,
|
||||
AtomComponents as Record<string, ComponentType<any>>
|
||||
)
|
||||
export const atomComponents: UIComponentRegistry = {
|
||||
...buildRegistryFromNames(
|
||||
atomRegistryNames,
|
||||
AtomComponents as Record<string, ComponentType<any>>
|
||||
),
|
||||
DataList: (AtomComponents as Record<string, ComponentType<any>>).DataList,
|
||||
DataTable: (AtomComponents as Record<string, ComponentType<any>>).DataTable,
|
||||
MetricCard: (AtomComponents as Record<string, ComponentType<any>>).MetricCard,
|
||||
Timeline: (AtomComponents as Record<string, ComponentType<any>>).Timeline,
|
||||
}
|
||||
|
||||
export const moleculeComponents: UIComponentRegistry = buildRegistryFromNames(
|
||||
moleculeRegistryNames,
|
||||
|
||||
@@ -74,113 +74,137 @@ export const stateBindingsDemoSchema: PageSchema = {
|
||||
],
|
||||
}
|
||||
|
||||
export const feedbackAtomsDemoSchema: PageSchema = {
|
||||
id: 'feedback-atoms-demo',
|
||||
name: 'Feedback Atoms Demo',
|
||||
export const dataComponentsDemoSchema: PageSchema = {
|
||||
id: 'data-components-demo',
|
||||
name: 'Data Components Demo',
|
||||
layout: {
|
||||
type: 'single',
|
||||
},
|
||||
dataSources: [
|
||||
{
|
||||
id: 'errorCount',
|
||||
id: 'metricCards',
|
||||
type: 'static',
|
||||
defaultValue: 3,
|
||||
defaultValue: [
|
||||
{ label: 'Active Users', value: 1248, trend: { value: 12.4, direction: 'up' } },
|
||||
{ label: 'Churn Rate', value: '3.2%', trend: { value: 1.1, direction: 'down' } },
|
||||
{ label: 'Net Revenue', value: '$48.3k', trend: { value: 6.8, direction: 'up' } },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'showNotification',
|
||||
id: 'tableColumns',
|
||||
type: 'static',
|
||||
defaultValue: true,
|
||||
defaultValue: [
|
||||
{ key: 'initiative', header: 'Initiative' },
|
||||
{ key: 'owner', header: 'Owner' },
|
||||
{ key: 'status', header: 'Status' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'statusType',
|
||||
id: 'tableRows',
|
||||
type: 'static',
|
||||
defaultValue: 'saved',
|
||||
defaultValue: [
|
||||
{ initiative: 'Landing Page', owner: 'Avery', status: 'In Progress' },
|
||||
{ initiative: 'Retention Emails', owner: 'Jordan', status: 'Review' },
|
||||
{ initiative: 'Billing Update', owner: 'Riley', status: 'Done' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'listItems',
|
||||
type: 'static',
|
||||
defaultValue: ['Prepare briefing deck', 'Confirm stakeholder approvals', 'Publish roadmap update'],
|
||||
},
|
||||
{
|
||||
id: 'timelineItems',
|
||||
type: 'static',
|
||||
defaultValue: [
|
||||
{
|
||||
title: 'Kickoff',
|
||||
description: 'Align on scope and milestones',
|
||||
timestamp: 'Mon 9:00 AM',
|
||||
status: 'completed',
|
||||
},
|
||||
{
|
||||
title: 'Execution',
|
||||
description: 'Deliver initial workstream',
|
||||
timestamp: 'Tue 11:00 AM',
|
||||
status: 'current',
|
||||
},
|
||||
{
|
||||
title: 'Review',
|
||||
description: 'Stakeholder walkthrough',
|
||||
timestamp: 'Thu 3:00 PM',
|
||||
status: 'pending',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
components: [
|
||||
{
|
||||
id: 'feedback-atoms-root',
|
||||
id: 'data-components-root',
|
||||
type: 'div',
|
||||
props: {
|
||||
className: 'space-y-6 rounded-lg border border-border bg-card p-6',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
id: 'feedback-atoms-title',
|
||||
id: 'data-components-title',
|
||||
type: 'Heading',
|
||||
props: {
|
||||
className: 'text-lg font-semibold',
|
||||
children: 'Feedback Atoms',
|
||||
className: 'text-xl font-semibold',
|
||||
children: 'Data Components Showcase',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'feedback-atoms-row',
|
||||
id: 'data-components-metrics-grid',
|
||||
type: 'div',
|
||||
props: {
|
||||
className: 'flex flex-wrap items-center gap-6',
|
||||
className: 'grid gap-4 md:grid-cols-3',
|
||||
},
|
||||
loop: {
|
||||
source: 'metricCards',
|
||||
itemVar: 'metricCard',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
id: 'feedback-atoms-status-icon',
|
||||
type: 'StatusIcon',
|
||||
props: {
|
||||
animate: true,
|
||||
size: 18,
|
||||
},
|
||||
id: 'data-components-metric-card',
|
||||
type: 'MetricCard',
|
||||
bindings: {
|
||||
type: {
|
||||
source: 'statusType',
|
||||
sourceType: 'data',
|
||||
},
|
||||
label: { sourceType: 'bindings', source: 'metricCard', path: 'label' },
|
||||
value: { sourceType: 'bindings', source: 'metricCard', path: 'value' },
|
||||
trend: { sourceType: 'bindings', source: 'metricCard', path: 'trend' },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'feedback-atoms-badge-wrapper',
|
||||
type: 'div',
|
||||
props: {
|
||||
className: 'relative h-10 w-10 rounded-full bg-muted',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
id: 'feedback-atoms-error-badge',
|
||||
type: 'ErrorBadge',
|
||||
props: {
|
||||
variant: 'destructive',
|
||||
size: 'md',
|
||||
},
|
||||
bindings: {
|
||||
count: {
|
||||
source: 'errorCount',
|
||||
sourceType: 'data',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'feedback-atoms-notification',
|
||||
type: 'Notification',
|
||||
id: 'data-components-table',
|
||||
type: 'DataTable',
|
||||
props: {
|
||||
type: 'info',
|
||||
title: 'Heads up!',
|
||||
message: 'You have unsent changes ready to sync.',
|
||||
className: 'bg-background',
|
||||
emptyMessage: 'No initiatives found',
|
||||
},
|
||||
conditional: {
|
||||
if: 'data.showNotification',
|
||||
bindings: {
|
||||
columns: { source: 'tableColumns', sourceType: 'data' },
|
||||
data: { source: 'tableRows', sourceType: 'data' },
|
||||
},
|
||||
events: {
|
||||
onClose: {
|
||||
actions: [
|
||||
{
|
||||
id: 'dismiss-notification',
|
||||
type: 'set-value',
|
||||
target: 'showNotification',
|
||||
value: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'data-components-list',
|
||||
type: 'DataList',
|
||||
props: {
|
||||
className: 'space-y-3',
|
||||
itemClassName: 'rounded-md border border-border bg-card/50 px-4 py-2 text-sm',
|
||||
emptyMessage: 'No action items',
|
||||
},
|
||||
bindings: {
|
||||
items: { source: 'listItems', sourceType: 'data' },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'data-components-timeline',
|
||||
type: 'Timeline',
|
||||
bindings: {
|
||||
items: { source: 'timelineItems', sourceType: 'data' },
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -8,6 +8,7 @@ export type ComponentType =
|
||||
| 'Alert' | 'InfoBox' | 'EmptyState' | 'StatusBadge'
|
||||
| 'ErrorBadge' | 'Notification' | 'StatusIcon'
|
||||
| 'Table' | 'KeyValue' | 'StatCard' | 'DataCard' | 'SearchInput' | 'ActionBar'
|
||||
| 'DataList' | 'DataTable' | 'MetricCard' | 'Timeline'
|
||||
| 'AppBranding' | 'LabelWithBadge' | 'EmptyEditorState' | 'LoadingFallback' | 'LoadingState' | 'NavigationGroupHeader'
|
||||
|
||||
export type ActionType =
|
||||
|
||||
Reference in New Issue
Block a user