diff --git a/JSON_COMPONENTS.md b/JSON_COMPONENTS.md index d3b497e..f2e943e 100644 --- a/JSON_COMPONENTS.md +++ b/JSON_COMPONENTS.md @@ -92,8 +92,8 @@ Form inputs and interactive controls: - `Switch` - Toggle switch - `Slider` - Numeric range slider - `NumberInput` - Numeric input with increment/decrement -- `DatePicker` - Date selection (planned) -- `FileUpload` - File upload control (planned) +- `DatePicker` - Date selection +- `FileUpload` - File upload control ### Display Components (16) Presentation and visual elements: @@ -110,9 +110,9 @@ Presentation and visual elements: - `Spinner` - Loading spinner - `Skeleton` - Loading placeholder - `Separator` - Visual divider -- `CircularProgress` - Circular indicator (planned) -- `ProgressBar` - Linear progress (planned) -- `Divider` - Section divider (planned) +- `CircularProgress` - Circular indicator +- `ProgressBar` - Linear progress +- `Divider` - Section divider ### Navigation Components (3) Navigation and routing: diff --git a/json-components-list.json b/json-components-list.json index 0c9a2ed..953f060 100644 --- a/json-components-list.json +++ b/json-components-list.json @@ -172,7 +172,7 @@ "category": "input", "canHaveChildren": false, "description": "Date selection input", - "status": "planned" + "status": "supported" }, { "type": "FileUpload", @@ -180,7 +180,7 @@ "category": "input", "canHaveChildren": false, "description": "File upload control", - "status": "planned" + "status": "supported" }, { "type": "Text", @@ -268,7 +268,7 @@ "category": "display", "canHaveChildren": false, "description": "Visual section divider", - "status": "planned" + "status": "supported" }, { "type": "Progress", @@ -284,7 +284,7 @@ "category": "display", "canHaveChildren": false, "description": "Linear progress bar", - "status": "planned" + "status": "supported" }, { "type": "CircularProgress", @@ -292,7 +292,7 @@ "category": "display", "canHaveChildren": false, "description": "Circular progress indicator", - "status": "planned" + "status": "supported" }, { "type": "Spinner", diff --git a/json-components-registry.json b/json-components-registry.json index e3f8c9c..78ef6c5 100644 --- a/json-components-registry.json +++ b/json-components-registry.json @@ -2,7 +2,7 @@ "$schema": "./schemas/json-components-registry-schema.json", "version": "2.0.0", "description": "Registry of all components in the application", - "lastUpdated": "2026-01-17T22:10:22.582Z", + "lastUpdated": "2026-01-18T12:05:00.000Z", "categories": { "layout": "Layout and container components", "input": "Form inputs and interactive controls", @@ -322,7 +322,7 @@ "category": "input", "canHaveChildren": false, "description": "Date selection input", - "status": "planned", + "status": "supported", "source": "atoms" }, { @@ -331,7 +331,7 @@ "category": "input", "canHaveChildren": false, "description": "File upload control", - "status": "planned", + "status": "supported", "source": "atoms" }, { @@ -611,7 +611,7 @@ "category": "display", "canHaveChildren": false, "description": "Circular progress indicator", - "status": "planned", + "status": "supported", "source": "atoms" }, { @@ -629,7 +629,7 @@ "category": "display", "canHaveChildren": false, "description": "Visual section divider", - "status": "planned", + "status": "supported", "source": "atoms" }, { @@ -719,7 +719,7 @@ "category": "display", "canHaveChildren": false, "description": "Linear progress bar", - "status": "planned", + "status": "supported", "source": "atoms" }, { @@ -836,29 +836,10 @@ "name": "Breadcrumb", "category": "navigation", "canHaveChildren": false, - "description": "Navigation breadcrumb trail", - "status": "planned", + "description": "Navigation breadcrumb trail using the atoms/BreadcrumbNav JSON-safe items prop", + "status": "supported", "source": "atoms" }, - { - "type": "Breadcrumb", - "name": "Breadcrumb", - "category": "navigation", - "canHaveChildren": false, - "description": "Navigation breadcrumb trail", - "status": "json-compatible", - "source": "molecules", - "jsonCompatible": true - }, - { - "type": "Breadcrumb", - "name": "Breadcrumb", - "category": "navigation", - "canHaveChildren": false, - "description": "Navigation breadcrumb trail", - "status": "planned", - "source": "ui" - }, { "type": "ContextMenu", "name": "ContextMenu", @@ -1088,7 +1069,7 @@ "category": "feedback", "canHaveChildren": false, "description": "Error state badge", - "status": "planned", + "status": "supported", "source": "atoms" }, { @@ -1164,7 +1145,7 @@ "category": "feedback", "canHaveChildren": true, "description": "Toast notification", - "status": "planned", + "status": "supported", "source": "atoms" }, { @@ -1201,7 +1182,7 @@ "category": "feedback", "canHaveChildren": false, "description": "Status indicator icon", - "status": "planned", + "status": "supported", "source": "atoms" }, { @@ -2043,24 +2024,24 @@ ], "statistics": { "total": 219, - "supported": 154, - "planned": 10, + "supported": 157, + "planned": 7, "jsonCompatible": 14, "maybeJsonCompatible": 41, "byCategory": { "layout": 25, "input": 34, "display": 31, - "navigation": 17, + "navigation": 15, "feedback": 23, "data": 20, "custom": 69 }, "bySource": { "atoms": 117, - "molecules": 41, + "molecules": 40, "organisms": 15, - "ui": 46 + "ui": 45 } } } diff --git a/src/components/JSONUIPage.tsx b/src/components/JSONUIPage.tsx index 55f189c..08edaad 100644 --- a/src/components/JSONUIPage.tsx +++ b/src/components/JSONUIPage.tsx @@ -78,6 +78,16 @@ export function JSONUIPage({ jsonConfig }: JSONUIPageProps) { updateDataField('formData', action.params.field, event) } break + case 'update-date': + if (action.params?.field) { + updateDataField('formData', action.params.field, event) + } + break + case 'update-files': + if (action.params?.field) { + updateDataField('formData', action.params.field, event) + } + break case 'submit-form': toast.success('Form submitted!') console.log('Form data:', dataMap.formData) diff --git a/src/components/JSONUIShowcasePage.tsx b/src/components/JSONUIShowcasePage.tsx index 1cd4c08..1926584 100644 --- a/src/components/JSONUIShowcasePage.tsx +++ b/src/components/JSONUIShowcasePage.tsx @@ -3,12 +3,13 @@ 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 { dataComponentsDemoSchema } from '@/schemas/page-schemas' +import pageSchemasJson from '@/schemas/page-schemas.json' import todoListJson from '@/schemas/todo-list.json' import newMoleculesShowcaseJson from '@/schemas/new-molecules-showcase.json' const todoListSchema = hydrateSchema(todoListJson) const newMoleculesShowcaseSchema = hydrateSchema(newMoleculesShowcaseJson) +const dataComponentsDemoSchema = hydrateSchema(pageSchemasJson.dataComponentsDemoSchema) export function JSONUIShowcasePage() { return ( @@ -25,6 +26,7 @@ export function JSONUIShowcasePage() { Atomic Components + Feedback Atoms New Molecules Data Components JSON Dashboard @@ -36,6 +38,10 @@ export function JSONUIShowcasePage() { + + + + diff --git a/src/components/atoms/Breadcrumb.tsx b/src/components/atoms/Breadcrumb.tsx index 3964503..4cce34b 100644 --- a/src/components/atoms/Breadcrumb.tsx +++ b/src/components/atoms/Breadcrumb.tsx @@ -17,19 +17,19 @@ export function BreadcrumbNav({ items, className }: BreadcrumbNavProps) { ) } + +export const Breadcrumb = BreadcrumbNav diff --git a/src/components/atoms/ComponentPaletteItem.tsx b/src/components/atoms/ComponentPaletteItem.tsx index a4a89d4..5bc47e1 100644 --- a/src/components/atoms/ComponentPaletteItem.tsx +++ b/src/components/atoms/ComponentPaletteItem.tsx @@ -1,4 +1,4 @@ -import { ComponentDefinition } from '@/lib/component-definitions-utils' +import { ComponentDefinition } from '@/lib/component-definition-types' import { Card } from '@/components/ui/card' import * as Icons from '@phosphor-icons/react' import { cn } from '@/lib/utils' diff --git a/src/components/atoms/ComponentTreeNode.tsx b/src/components/atoms/ComponentTreeNode.tsx index c9a2b70..1655ea2 100644 --- a/src/components/atoms/ComponentTreeNode.tsx +++ b/src/components/atoms/ComponentTreeNode.tsx @@ -1,5 +1,5 @@ import { UIComponent } from '@/types/json-ui' -import { getComponentDef } from '@/lib/component-definitions-utils' +import { getComponentDef } from '@/lib/component-definition-utils' import { cn } from '@/lib/utils' import * as Icons from '@phosphor-icons/react' diff --git a/src/components/atoms/index.ts b/src/components/atoms/index.ts index 75fde87..fb449ff 100644 --- a/src/components/atoms/index.ts +++ b/src/components/atoms/index.ts @@ -54,7 +54,7 @@ export { Timestamp } from './Timestamp' export { ScrollArea } from './ScrollArea' export { Tag } from './Tag' -export { BreadcrumbNav } from './Breadcrumb' +export { Breadcrumb, BreadcrumbNav } from './Breadcrumb' export { IconText } from './IconText' export { TextArea } from './TextArea' export { Input } from './Input' @@ -118,4 +118,3 @@ export { MetricDisplay } from './MetricDisplay' export { KeyValue } from './KeyValue' export { EmptyMessage } from './EmptyMessage' export { StepIndicator } from './StepIndicator' - diff --git a/src/components/molecules/CanvasRenderer.tsx b/src/components/molecules/CanvasRenderer.tsx index 7225f47..e31ca54 100644 --- a/src/components/molecules/CanvasRenderer.tsx +++ b/src/components/molecules/CanvasRenderer.tsx @@ -1,6 +1,6 @@ import { UIComponent } from '@/types/json-ui' import { getUIComponent } from '@/lib/json-ui/component-registry' -import { getComponentDef } from '@/lib/component-definitions-utils' +import { getComponentDef } from '@/lib/component-definition-utils' import { cn } from '@/lib/utils' import { createElement, ReactNode } from 'react' diff --git a/src/components/molecules/ComponentPalette.tsx b/src/components/molecules/ComponentPalette.tsx index 17792db..1571f47 100644 --- a/src/components/molecules/ComponentPalette.tsx +++ b/src/components/molecules/ComponentPalette.tsx @@ -1,4 +1,5 @@ -import { ComponentDefinition, getCategoryComponents } from '@/lib/component-definitions-utils' +import { ComponentDefinition } from '@/lib/component-definition-types' +import { getCategoryComponents } from '@/lib/component-definition-utils' import { ComponentPaletteItem } from '@/components/atoms/ComponentPaletteItem' import { PanelHeader, Stack } from '@/components/atoms' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' diff --git a/src/components/molecules/PropertyEditor.tsx b/src/components/molecules/PropertyEditor.tsx index d8d1485..cdbe172 100644 --- a/src/components/molecules/PropertyEditor.tsx +++ b/src/components/molecules/PropertyEditor.tsx @@ -1,7 +1,7 @@ import { UIComponent } from '@/types/json-ui' import { ScrollArea } from '@/components/ui/scroll-area' import { Separator } from '@/components/ui/separator' -import { getComponentDef } from '@/lib/component-definitions-utils' +import { getComponentDef } from '@/lib/component-definition-utils' import { PropertyEditorEmptyState } from '@/components/molecules/property-editor/PropertyEditorEmptyState' import { propertyEditorConfig } from '@/components/molecules/property-editor/propertyEditorConfig' import { PropertyEditorHeader } from '@/components/molecules/property-editor/PropertyEditorHeader' diff --git a/src/components/organisms/SchemaEditorLayout.tsx b/src/components/organisms/SchemaEditorLayout.tsx index e41a1b0..aea9be3 100644 --- a/src/components/organisms/SchemaEditorLayout.tsx +++ b/src/components/organisms/SchemaEditorLayout.tsx @@ -1,5 +1,5 @@ import { UIComponent, PageSchema } from '@/types/json-ui' -import { ComponentDefinition } from '@/lib/component-definitions-utils' +import { ComponentDefinition } from '@/lib/component-definition-types' import { SchemaEditorToolbar } from './SchemaEditorToolbar' import { SchemaEditorSidebar } from './SchemaEditorSidebar' import { SchemaEditorCanvas } from './SchemaEditorCanvas' diff --git a/src/components/organisms/SchemaEditorSidebar.tsx b/src/components/organisms/SchemaEditorSidebar.tsx index ee71e03..dfba600 100644 --- a/src/components/organisms/SchemaEditorSidebar.tsx +++ b/src/components/organisms/SchemaEditorSidebar.tsx @@ -1,5 +1,5 @@ import { ComponentPalette } from '@/components/molecules/ComponentPalette' -import { ComponentDefinition } from '@/lib/component-definitions-utils' +import { ComponentDefinition } from '@/lib/component-definition-types' interface SchemaEditorSidebarProps { onDragStart: (component: ComponentDefinition, e: React.DragEvent) => void diff --git a/src/components/schema-editor/SchemaEditorWorkspace.tsx b/src/components/schema-editor/SchemaEditorWorkspace.tsx index 0628f0a..c64d9a1 100644 --- a/src/components/schema-editor/SchemaEditorWorkspace.tsx +++ b/src/components/schema-editor/SchemaEditorWorkspace.tsx @@ -2,7 +2,7 @@ import { useSchemaEditor } from '@/hooks/ui/use-schema-editor' import { useDragDrop } from '@/hooks/ui/use-drag-drop' import { useJsonExport } from '@/hooks/ui/use-json-export' import { SchemaEditorLayout } from '@/components/organisms' -import { ComponentDefinition } from '@/lib/component-definitions-utils' +import { ComponentDefinition } from '@/lib/component-definition-types' import { UIComponent, PageSchema } from '@/types/json-ui' import { toast } from 'sonner' import { schemaEditorConfig } from '@/components/schema-editor/schemaEditorConfig' diff --git a/src/config/ui-examples/form.json b/src/config/ui-examples/form.json index ebc87c1..e0a3428 100644 --- a/src/config/ui-examples/form.json +++ b/src/config/ui-examples/form.json @@ -130,6 +130,37 @@ } ] }, + { + "id": "birthdate-field", + "type": "div", + "className": "space-y-2", + "children": [ + { + "id": "birthdate-label", + "type": "Label", + "props": { + "htmlFor": "birthDate" + }, + "children": "Birth date" + }, + { + "id": "birthdate-input", + "type": "DatePicker", + "props": { + "placeholder": "Select a date" + }, + "dataBinding": "formData.birthDate", + "events": { + "onChange": { + "action": "update-date", + "payload": { + "field": "birthDate" + } + } + } + } + ] + }, { "id": "bio-field", "type": "div", @@ -159,6 +190,36 @@ } ] }, + { + "id": "resume-field", + "type": "div", + "className": "space-y-2", + "children": [ + { + "id": "resume-label", + "type": "Label", + "props": { + "htmlFor": "resume" + }, + "children": "Resume" + }, + { + "id": "resume-upload", + "type": "FileUpload", + "props": { + "accept": ".pdf,.doc,.docx" + }, + "events": { + "onFilesSelected": { + "action": "update-files", + "payload": { + "field": "resumeFiles" + } + } + } + } + ] + }, { "id": "subscribe-field", "type": "div", @@ -234,6 +295,8 @@ "email": "", "password": "", "bio": "", + "birthDate": null, + "resumeFiles": [], "subscribe": false } } diff --git a/src/lib/component-definition-types.ts b/src/lib/component-definition-types.ts new file mode 100644 index 0000000..ead5aea --- /dev/null +++ b/src/lib/component-definition-types.ts @@ -0,0 +1,27 @@ +import { ComponentType } from '@/types/json-ui' + +export interface ComponentDefinition { + type: ComponentType + label: string + category: 'layout' | 'input' | 'display' | 'navigation' | 'feedback' | 'data' | 'custom' + icon: string + defaultProps?: Record + canHaveChildren?: boolean + props?: ComponentPropDefinition[] + events?: ComponentEventDefinition[] +} + +export interface ComponentPropDefinition { + name: string + type: string + description: string + required?: boolean + defaultValue?: string + options?: string[] + supportsBinding?: boolean +} + +export interface ComponentEventDefinition { + name: string + description: string +} diff --git a/src/lib/component-definition-utils.ts b/src/lib/component-definition-utils.ts new file mode 100644 index 0000000..9796af7 --- /dev/null +++ b/src/lib/component-definition-utils.ts @@ -0,0 +1,13 @@ +import componentDefinitionsData from '@/lib/component-definitions.json' +import { ComponentDefinition } from '@/lib/component-definition-types' +import { ComponentType } from '@/types/json-ui' + +export const componentDefinitions = componentDefinitionsData as ComponentDefinition[] + +export function getCategoryComponents(category: string): ComponentDefinition[] { + return componentDefinitions.filter(c => c.category === category) +} + +export function getComponentDef(type: ComponentType): ComponentDefinition | undefined { + return componentDefinitions.find(c => c.type === type) +} diff --git a/src/lib/component-definitions.json b/src/lib/component-definitions.json index 0176cb3..a0ad390 100644 --- a/src/lib/component-definitions.json +++ b/src/lib/component-definitions.json @@ -209,6 +209,19 @@ "canHaveChildren": true, "defaultProps": { "href": "#", "children": "Link" } }, + { + "type": "Breadcrumb", + "label": "Breadcrumb", + "category": "navigation", + "icon": "CaretRight", + "canHaveChildren": false, + "defaultProps": { + "items": [ + { "label": "Home", "href": "/" }, + { "label": "Current" } + ] + } + }, { "type": "Alert", "label": "Alert", @@ -240,6 +253,107 @@ "icon": "Circle", "defaultProps": { "status": "active", "children": "Active" } }, + { + "type": "ErrorBadge", + "label": "Error Badge", + "category": "feedback", + "icon": "WarningCircle", + "defaultProps": { "count": 3, "variant": "destructive", "size": "md" }, + "props": [ + { + "name": "count", + "type": "number", + "description": "Number of errors to display. Hidden when set to 0.", + "required": true, + "supportsBinding": true + }, + { + "name": "variant", + "type": "string", + "description": "Visual variant for the badge.", + "defaultValue": "destructive", + "options": ["default", "destructive"] + }, + { + "name": "size", + "type": "string", + "description": "Badge size.", + "defaultValue": "md", + "options": ["sm", "md"] + } + ] + }, + { + "type": "Notification", + "label": "Notification", + "category": "feedback", + "icon": "Info", + "defaultProps": { "type": "info", "title": "Notification", "message": "Details go here." }, + "props": [ + { + "name": "type", + "type": "string", + "description": "Notification style variant.", + "required": true, + "options": ["info", "success", "warning", "error"] + }, + { + "name": "title", + "type": "string", + "description": "Primary notification title.", + "required": true, + "supportsBinding": true + }, + { + "name": "message", + "type": "string", + "description": "Optional supporting message text.", + "supportsBinding": true + }, + { + "name": "className", + "type": "string", + "description": "Optional custom classes for spacing or layout tweaks." + } + ], + "events": [ + { + "name": "onClose", + "description": "Fires when the close button is clicked. Bind to dismiss or trigger an action." + } + ] + }, + { + "type": "StatusIcon", + "label": "Status Icon", + "category": "feedback", + "icon": "CheckCircle", + "defaultProps": { "type": "saved", "size": 14, "animate": false }, + "props": [ + { + "name": "type", + "type": "string", + "description": "Status icon style.", + "required": true, + "supportsBinding": true, + "options": ["saved", "synced"] + }, + { + "name": "size", + "type": "number", + "description": "Icon size in pixels.", + "defaultValue": "14", + "supportsBinding": true + }, + { + "name": "animate", + "type": "boolean", + "description": "Applies entry animation when true.", + "defaultValue": "false", + "supportsBinding": true + } + ] + }, { "type": "List", "label": "List", diff --git a/src/lib/json-ui/component-registry.ts b/src/lib/json-ui/component-registry.ts index 507a5d1..6206321 100644 --- a/src/lib/json-ui/component-registry.ts +++ b/src/lib/json-ui/component-registry.ts @@ -147,6 +147,11 @@ export const atomComponents: UIComponentRegistry = { Timeline: (AtomComponents as Record>).Timeline, } +const breadcrumbComponent = AtomComponents.Breadcrumb ?? AtomComponents.BreadcrumbNav +if (breadcrumbComponent) { + atomComponents.Breadcrumb = breadcrumbComponent as ComponentType +} + export const moleculeComponents: UIComponentRegistry = buildRegistryFromNames( moleculeRegistryNames, MoleculeComponents as Record> diff --git a/src/schemas/page-schemas.json b/src/schemas/page-schemas.json new file mode 100644 index 0000000..0a38f9a --- /dev/null +++ b/src/schemas/page-schemas.json @@ -0,0 +1,212 @@ +{ + "stateBindingsDemoSchema": { + "id": "state-bindings-demo", + "name": "State & Bindings Demo", + "layout": { + "type": "single" + }, + "dataSources": [ + { + "id": "statusItems", + "type": "static", + "defaultValue": ["KV Ready", "Components Loaded", "Sync Enabled"] + } + ], + "components": [ + { + "id": "state-demo-root", + "type": "div", + "props": { + "className": "space-y-4 rounded-lg border border-border bg-card p-6" + }, + "children": [ + { + "id": "state-demo-title", + "type": "Heading", + "props": { + "className": "text-xl font-semibold", + "children": "Renderer State Binding Demo" + } + }, + { + "id": "state-demo-theme", + "type": "Text", + "props": { + "className": "text-sm text-muted-foreground" + }, + "bindings": { + "children": { + "sourceType": "state", + "source": "settings", + "path": "settings.theme" + } + } + }, + { + "id": "state-demo-list", + "type": "div", + "props": { + "className": "space-y-2" + }, + "loop": { + "source": "statusItems", + "itemVar": "statusItem" + }, + "children": [ + { + "id": "state-demo-list-item", + "type": "Text", + "props": { + "className": "text-sm" + }, + "bindings": { + "children": { + "sourceType": "bindings", + "source": "statusItem" + } + } + } + ] + } + ] + } + ] + }, + "dataComponentsDemoSchema": { + "id": "data-components-demo", + "name": "Data Components Demo", + "layout": { + "type": "single" + }, + "dataSources": [ + { + "id": "metricCards", + "type": "static", + "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": "tableColumns", + "type": "static", + "defaultValue": [ + { "key": "initiative", "header": "Initiative" }, + { "key": "owner", "header": "Owner" }, + { "key": "status", "header": "Status" } + ] + }, + { + "id": "tableRows", + "type": "static", + "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": "data-components-root", + "type": "div", + "props": { + "className": "space-y-6 rounded-lg border border-border bg-card p-6" + }, + "children": [ + { + "id": "data-components-title", + "type": "Heading", + "props": { + "className": "text-xl font-semibold", + "children": "Data Components Showcase" + } + }, + { + "id": "data-components-metrics-grid", + "type": "div", + "props": { + "className": "grid gap-4 md:grid-cols-3" + }, + "loop": { + "source": "metricCards", + "itemVar": "metricCard" + }, + "children": [ + { + "id": "data-components-metric-card", + "type": "MetricCard", + "bindings": { + "label": { "sourceType": "bindings", "source": "metricCard", "path": "label" }, + "value": { "sourceType": "bindings", "source": "metricCard", "path": "value" }, + "trend": { "sourceType": "bindings", "source": "metricCard", "path": "trend" } + } + } + ] + }, + { + "id": "data-components-table", + "type": "DataTable", + "props": { + "className": "bg-background", + "emptyMessage": "No initiatives found" + }, + "bindings": { + "columns": { "source": "tableColumns", "sourceType": "data" }, + "data": { "source": "tableRows", "sourceType": "data" } + } + }, + { + "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" } + } + } + ] + } + ] + } +} diff --git a/src/schemas/page-schemas.ts b/src/schemas/page-schemas.ts deleted file mode 100644 index 68299c8..0000000 --- a/src/schemas/page-schemas.ts +++ /dev/null @@ -1,213 +0,0 @@ -import type { PageSchema } from '@/types/json-ui' - -export const stateBindingsDemoSchema: PageSchema = { - id: 'state-bindings-demo', - name: 'State & Bindings Demo', - layout: { - type: 'single', - }, - dataSources: [ - { - id: 'statusItems', - type: 'static', - defaultValue: ['KV Ready', 'Components Loaded', 'Sync Enabled'], - }, - ], - components: [ - { - id: 'state-demo-root', - type: 'div', - props: { - className: 'space-y-4 rounded-lg border border-border bg-card p-6', - }, - children: [ - { - id: 'state-demo-title', - type: 'Heading', - props: { - className: 'text-xl font-semibold', - children: 'Renderer State Binding Demo', - }, - }, - { - id: 'state-demo-theme', - type: 'Text', - props: { - className: 'text-sm text-muted-foreground', - }, - bindings: { - children: { - sourceType: 'state', - source: 'settings', - path: 'settings.theme', - }, - }, - }, - { - id: 'state-demo-list', - type: 'div', - props: { - className: 'space-y-2', - }, - loop: { - source: 'statusItems', - itemVar: 'statusItem', - }, - children: [ - { - id: 'state-demo-list-item', - type: 'Text', - props: { - className: 'text-sm', - }, - bindings: { - children: { - sourceType: 'bindings', - source: 'statusItem', - }, - }, - }, - ], - }, - ], - }, - ], -} - -export const dataComponentsDemoSchema: PageSchema = { - id: 'data-components-demo', - name: 'Data Components Demo', - layout: { - type: 'single', - }, - dataSources: [ - { - id: 'metricCards', - type: 'static', - 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: 'tableColumns', - type: 'static', - defaultValue: [ - { key: 'initiative', header: 'Initiative' }, - { key: 'owner', header: 'Owner' }, - { key: 'status', header: 'Status' }, - ], - }, - { - id: 'tableRows', - type: 'static', - 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: 'data-components-root', - type: 'div', - props: { - className: 'space-y-6 rounded-lg border border-border bg-card p-6', - }, - children: [ - { - id: 'data-components-title', - type: 'Heading', - props: { - className: 'text-xl font-semibold', - children: 'Data Components Showcase', - }, - }, - { - id: 'data-components-metrics-grid', - type: 'div', - props: { - className: 'grid gap-4 md:grid-cols-3', - }, - loop: { - source: 'metricCards', - itemVar: 'metricCard', - }, - children: [ - { - id: 'data-components-metric-card', - type: 'MetricCard', - bindings: { - label: { sourceType: 'bindings', source: 'metricCard', path: 'label' }, - value: { sourceType: 'bindings', source: 'metricCard', path: 'value' }, - trend: { sourceType: 'bindings', source: 'metricCard', path: 'trend' }, - }, - }, - ], - }, - { - id: 'data-components-table', - type: 'DataTable', - props: { - className: 'bg-background', - emptyMessage: 'No initiatives found', - }, - bindings: { - columns: { source: 'tableColumns', sourceType: 'data' }, - data: { source: 'tableRows', sourceType: 'data' }, - }, - }, - { - 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' }, - }, - }, - ], - }, - ], -} diff --git a/src/types/json-ui.ts b/src/types/json-ui.ts index 5bed643..69b1d39 100644 --- a/src/types/json-ui.ts +++ b/src/types/json-ui.ts @@ -2,10 +2,12 @@ export type ComponentType = | 'div' | 'section' | 'article' | 'header' | 'footer' | 'main' | 'Button' | 'Card' | 'CardHeader' | 'CardTitle' | 'CardDescription' | 'CardContent' | 'CardFooter' | 'Input' | 'TextArea' | 'Textarea' | 'Select' | 'Checkbox' | 'Radio' | 'Switch' | 'Slider' | 'NumberInput' + | 'DatePicker' | 'FileUpload' | 'Badge' | 'Progress' | 'Separator' | 'Tabs' | 'TabsContent' | 'TabsList' | 'TabsTrigger' | 'Dialog' | 'Text' | 'Heading' | 'Label' | 'List' | 'Grid' | 'Stack' | 'Flex' | 'Container' - | 'Link' | 'Image' | 'Avatar' | 'Code' | 'Tag' | 'Spinner' | 'Skeleton' + | 'Link' | 'Breadcrumb' | 'Image' | 'Avatar' | 'Code' | 'Tag' | 'Spinner' | 'Skeleton' | 'Alert' | 'InfoBox' | 'EmptyState' | 'StatusBadge' + | 'ErrorBadge' | 'Notification' | 'StatusIcon' | 'Table' | 'KeyValue' | 'StatCard' | 'DataCard' | 'SearchInput' | 'ActionBar' | 'DataList' | 'DataTable' | 'MetricCard' | 'Timeline' | 'AppBranding' | 'LabelWithBadge' | 'EmptyEditorState' | 'LoadingFallback' | 'LoadingState' | 'NavigationGroupHeader'