Add JSON UI support for feedback atoms

This commit is contained in:
2026-01-18 11:38:50 +00:00
parent fc209545c1
commit 0d82406e5f
5 changed files with 242 additions and 3 deletions

View File

@@ -1088,7 +1088,7 @@
"category": "feedback",
"canHaveChildren": false,
"description": "Error state badge",
"status": "planned",
"status": "supported",
"source": "atoms"
},
{
@@ -1164,7 +1164,7 @@
"category": "feedback",
"canHaveChildren": true,
"description": "Toast notification",
"status": "planned",
"status": "supported",
"source": "atoms"
},
{
@@ -1201,7 +1201,7 @@
"category": "feedback",
"canHaveChildren": false,
"description": "Status indicator icon",
"status": "planned",
"status": "supported",
"source": "atoms"
},
{

View File

@@ -3,6 +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 todoListJson from '@/schemas/todo-list.json'
import newMoleculesShowcaseJson from '@/schemas/new-molecules-showcase.json'
@@ -24,6 +25,7 @@ export function JSONUIShowcasePage() {
</div>
<TabsList className="w-full justify-start">
<TabsTrigger value="atomic">Atomic Components</TabsTrigger>
<TabsTrigger value="feedback">Feedback Atoms</TabsTrigger>
<TabsTrigger value="molecules">New Molecules</TabsTrigger>
<TabsTrigger value="dashboard">JSON Dashboard</TabsTrigger>
<TabsTrigger value="todos">JSON Todo List</TabsTrigger>
@@ -34,6 +36,10 @@ export function JSONUIShowcasePage() {
<TabsContent value="atomic" className="h-full m-0 data-[state=active]:block">
<AtomicComponentDemo />
</TabsContent>
<TabsContent value="feedback" className="h-full m-0 data-[state=active]:block">
<PageRenderer schema={feedbackAtomsDemoSchema} />
</TabsContent>
<TabsContent value="molecules" className="h-full m-0 data-[state=active]:block">
<PageRenderer schema={newMoleculesShowcaseSchema} />

View File

@@ -7,6 +7,23 @@ export interface ComponentDefinition {
icon: string
defaultProps?: Record<string, any>
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
}
export const componentDefinitions: ComponentDefinition[] = [
@@ -256,6 +273,107 @@ export const componentDefinitions: ComponentDefinition[] = [
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,
},
],
},
// Data Components
{
type: 'List',

View File

@@ -73,3 +73,117 @@ export const stateBindingsDemoSchema: PageSchema = {
},
],
}
export const feedbackAtomsDemoSchema: PageSchema = {
id: 'feedback-atoms-demo',
name: 'Feedback Atoms Demo',
layout: {
type: 'single',
},
dataSources: [
{
id: 'errorCount',
type: 'static',
defaultValue: 3,
},
{
id: 'showNotification',
type: 'static',
defaultValue: true,
},
{
id: 'statusType',
type: 'static',
defaultValue: 'saved',
},
],
components: [
{
id: 'feedback-atoms-root',
type: 'div',
props: {
className: 'space-y-6 rounded-lg border border-border bg-card p-6',
},
children: [
{
id: 'feedback-atoms-title',
type: 'Heading',
props: {
className: 'text-lg font-semibold',
children: 'Feedback Atoms',
},
},
{
id: 'feedback-atoms-row',
type: 'div',
props: {
className: 'flex flex-wrap items-center gap-6',
},
children: [
{
id: 'feedback-atoms-status-icon',
type: 'StatusIcon',
props: {
animate: true,
size: 18,
},
bindings: {
type: {
source: 'statusType',
sourceType: 'data',
},
},
},
{
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',
props: {
type: 'info',
title: 'Heads up!',
message: 'You have unsent changes ready to sync.',
},
conditional: {
if: 'data.showNotification',
},
events: {
onClose: {
actions: [
{
id: 'dismiss-notification',
type: 'set-value',
target: 'showNotification',
value: false,
},
],
},
},
},
],
},
],
}

View File

@@ -6,6 +6,7 @@ export type ComponentType =
| 'Text' | 'Heading' | 'Label' | 'List' | 'Grid' | 'Stack' | 'Flex' | 'Container'
| 'Link' | 'Image' | 'Avatar' | 'Code' | 'Tag' | 'Spinner' | 'Skeleton'
| 'Alert' | 'InfoBox' | 'EmptyState' | 'StatusBadge'
| 'ErrorBadge' | 'Notification' | 'StatusIcon'
| 'Table' | 'KeyValue' | 'StatCard' | 'DataCard' | 'SearchInput' | 'ActionBar'
| 'AppBranding' | 'LabelWithBadge' | 'EmptyEditorState' | 'LoadingFallback' | 'LoadingState' | 'NavigationGroupHeader'