feat: migrate Tier 3 atoms batch 1 - ActionButton through Badge (8 components)

Converts 8 atom components from TSX to JSON-driven architecture:
- ActionButton: Action trigger with optional tooltip
- ActionCard: Interactive card with icon and description
- ActionIcon: Icon mapper for common actions
- Alert: Variant-based alert notifications
- AppLogo: Branding logo component
- Avatar: User profile images with fallbacks
- AvatarGroup: Grouped avatar display with overflow
- Badge: Status and count indicators

Changes:
- Created interface files for all 8 components in src/lib/json-ui/interfaces/
- Created JSON definitions in src/components/json-definitions/
- Updated json-components.ts with imports and pure JSON exports
- Updated interfaces/index.ts with new exports
- Updated json-components-registry.json to mark all as jsonCompatible

All components are stateless pure JSON implementations using createJsonComponent.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-21 01:32:20 +00:00
parent 94d67dfed5
commit 982fee43ac
31 changed files with 1205 additions and 8 deletions

View File

@@ -75,7 +75,8 @@
"canHaveChildren": true,
"description": "Button with action icon",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "ActionCard",
@@ -84,7 +85,8 @@
"canHaveChildren": true,
"description": "ActionCard component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "ActionIcon",
@@ -93,7 +95,8 @@
"canHaveChildren": true,
"description": "ActionIcon component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "alert",
@@ -116,7 +119,8 @@
"canHaveChildren": true,
"description": "Alert notification message",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "AlertCircle",
@@ -166,7 +170,8 @@
"canHaveChildren": true,
"description": "AppLogo component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "ArrowLeft",
@@ -263,7 +268,8 @@
"canHaveChildren": false,
"description": "User avatar image",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "AvatarGroup",
@@ -272,7 +278,8 @@
"canHaveChildren": true,
"description": "Group of user avatars",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "badge",
@@ -295,7 +302,8 @@
"canHaveChildren": true,
"description": "Small status or count indicator",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "Badge as ShadcnBadge",

View File

@@ -0,0 +1,112 @@
{
"id": "action-button-root",
"type": "div",
"props": {
"className": "inline-flex"
},
"conditional": {
"if": "tooltip",
"then": {
"id": "action-button-with-tooltip",
"type": "div",
"children": [
{
"id": "action-button-tooltip-provider",
"type": "TooltipProvider",
"children": [
{
"id": "action-button-tooltip",
"type": "Tooltip",
"children": [
{
"id": "action-button-trigger",
"type": "TooltipTrigger",
"props": {
"asChild": true
},
"children": [
{
"id": "action-button-element",
"type": "Button",
"props": {
"disabled": "disabled",
"className": "className"
},
"bindings": {
"variant": "variant",
"size": "size"
},
"children": [
{
"id": "action-button-icon",
"type": "span",
"props": {
"className": "mr-2"
},
"bindings": {
"children": "icon"
},
"conditional": {
"if": "icon"
}
},
{
"id": "action-button-label",
"type": "span",
"bindings": {
"children": "label"
}
}
]
}
]
},
{
"id": "action-button-tooltip-content",
"type": "TooltipContent",
"bindings": {
"children": "tooltip"
}
}
]
}
]
}
]
},
"else": {
"id": "action-button-direct",
"type": "Button",
"props": {
"disabled": "disabled",
"className": "className"
},
"bindings": {
"variant": "variant",
"size": "size"
},
"children": [
{
"id": "action-button-icon-direct",
"type": "span",
"props": {
"className": "mr-2"
},
"bindings": {
"children": "icon"
},
"conditional": {
"if": "icon"
}
},
{
"id": "action-button-label-direct",
"type": "span",
"bindings": {
"children": "label"
}
}
]
}
}
}

View File

@@ -0,0 +1,89 @@
{
"id": "action-card-root",
"type": "Card",
"props": {
"className": "cursor-pointer transition-all hover:shadow-md hover:border-primary/50"
},
"bindings": {
"className": {
"source": "disabled",
"transform": "data ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer transition-all hover:shadow-md hover:border-primary/50'"
}
},
"children": [
{
"id": "action-card-content",
"type": "CardContent",
"props": {
"className": "p-4"
},
"children": [
{
"id": "action-card-flex",
"type": "Flex",
"props": {
"justify": "start",
"align": "start",
"gap": "md",
"className": "items-start gap-3"
},
"children": [
{
"id": "action-card-icon-wrapper",
"type": "div",
"props": {
"className": "flex-shrink-0 p-2 rounded-lg bg-primary/10 text-primary"
},
"bindings": {
"children": "icon"
},
"conditional": {
"if": "icon"
}
},
{
"id": "action-card-text-container",
"type": "div",
"props": {
"className": "flex-1 min-w-0"
},
"children": [
{
"id": "action-card-title",
"type": "div",
"props": {
"className": "font-semibold text-sm mb-1"
},
"bindings": {
"children": "title"
}
},
{
"id": "action-card-description",
"type": "div",
"props": {
"className": "text-xs text-muted-foreground line-clamp-2"
},
"bindings": {
"children": "description"
},
"conditional": {
"if": "description"
}
}
]
},
{
"id": "action-card-caret",
"type": "CaretRight",
"props": {
"size": 16,
"className": "flex-shrink-0 text-muted-foreground"
}
}
]
}
]
}
]
}

View File

@@ -0,0 +1,10 @@
{
"id": "action-icon-root",
"type": "ActionIcon",
"bindings": {
"action": "action",
"size": "size",
"weight": "weight",
"className": "className"
}
}

View File

@@ -0,0 +1,58 @@
{
"id": "alert-root",
"type": "div",
"props": {
"role": "alert",
"className": "flex gap-3 p-4 rounded-lg border"
},
"bindings": {
"className": {
"source": "variant",
"transform": "(() => { const config = { info: { classes: 'bg-blue-50 border-blue-200 text-blue-900' }, warning: { classes: 'bg-yellow-50 border-yellow-200 text-yellow-900' }, success: { classes: 'bg-green-50 border-green-200 text-green-900' }, error: { classes: 'bg-red-50 border-red-200 text-red-900' } }; return 'flex gap-3 p-4 rounded-lg border ' + (config[data]?.classes || config.info.classes); })()"
}
},
"children": [
{
"id": "alert-icon",
"type": "AlertIcon",
"bindings": {
"variant": "variant"
},
"props": {
"className": "flex-shrink-0 mt-0.5"
}
},
{
"id": "alert-content",
"type": "div",
"props": {
"className": "flex-1"
},
"children": [
{
"id": "alert-title",
"type": "div",
"props": {
"className": "font-semibold mb-1"
},
"bindings": {
"children": "title"
},
"conditional": {
"if": "title"
}
},
{
"id": "alert-message",
"type": "div",
"props": {
"className": "text-sm"
},
"bindings": {
"children": "children"
}
}
]
}
]
}

View File

@@ -0,0 +1,18 @@
{
"id": "app-logo-root",
"type": "div",
"props": {
"className": "w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-gradient-to-br from-primary to-accent flex items-center justify-center shrink-0"
},
"children": [
{
"id": "app-logo-icon",
"type": "Code",
"props": {
"size": 20,
"weight": "duotone",
"className": "text-white sm:w-6 sm:h-6"
}
}
]
}

View File

@@ -0,0 +1,50 @@
{
"id": "avatar-group-root",
"type": "div",
"bindings": {
"className": {
"source": "className",
"transform": "data ? 'flex -space-x-2 ' + data : 'flex -space-x-2'"
}
},
"children": [
{
"id": "avatar-group-list",
"type": "AvatarList",
"bindings": {
"avatars": "avatars",
"max": "max",
"size": "size"
}
},
{
"id": "avatar-group-remainder",
"type": "div",
"bindings": {
"className": {
"source": "size",
"transform": "(() => { const sizeClasses = { xs: 'h-6 w-6 text-xs', sm: 'h-8 w-8 text-xs', md: 'h-10 w-10 text-sm', lg: 'h-12 w-12 text-base' }; return 'relative inline-flex items-center justify-center rounded-full border-2 border-background bg-muted ' + (sizeClasses[data] || sizeClasses.md); })()"
}
},
"conditional": {
"if": "remainingCount",
"transform": "avatars.length - (max || 5) > 0"
},
"children": [
{
"id": "avatar-group-count",
"type": "span",
"props": {
"className": "font-medium text-foreground"
},
"bindings": {
"children": {
"source": "avatars",
"transform": "`+${Math.max(data.length - (max || 5), 0)}`"
}
}
}
]
}
]
}

View File

@@ -0,0 +1,37 @@
{
"id": "avatar-root",
"type": "div",
"bindings": {
"className": {
"source": "size",
"transform": "(() => { const sizeClasses = { xs: 'w-6 h-6 text-xs', sm: 'w-8 h-8 text-sm', md: 'w-10 h-10 text-base', lg: 'w-12 h-12 text-lg', xl: 'w-16 h-16 text-xl' }; return 'relative inline-flex items-center justify-center rounded-full bg-muted overflow-hidden ' + (sizeClasses[data] || sizeClasses.md); })()"
}
},
"conditional": {
"if": "src",
"then": {
"id": "avatar-image",
"type": "img",
"bindings": {
"src": "src",
"alt": "alt"
},
"props": {
"className": "w-full h-full object-cover"
}
},
"else": {
"id": "avatar-fallback",
"type": "span",
"props": {
"className": "font-medium text-muted-foreground"
},
"bindings": {
"children": {
"source": "fallback",
"transform": "data || (props.alt?.slice(0, 2).toUpperCase()) || '?'"
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
{
"id": "badge-root",
"type": "Badge",
"bindings": {
"variant": "variant",
"className": {
"source": "size",
"transform": "(() => { const sizeClasses = { sm: 'text-xs px-2 py-0.5', md: 'text-sm px-2.5 py-0.5', lg: 'text-base px-3 py-1' }; return 'inline-flex items-center gap-1.5 ' + (sizeClasses[data] || sizeClasses.md); })()"
}
},
"children": [
{
"id": "badge-icon",
"type": "span",
"props": {
"className": "flex-shrink-0"
},
"bindings": {
"children": "icon"
},
"conditional": {
"if": "icon"
}
},
{
"id": "badge-content",
"type": "span",
"bindings": {
"children": "children"
}
}
]
}

View File

@@ -0,0 +1,122 @@
{
"id": "breadcrumb",
"type": "nav",
"bindings": {
"aria-label": {
"source": null,
"transform": "'Breadcrumb'"
},
"className": {
"source": ["items", "className"],
"transform": "const cn = (classes) => classes.filter(Boolean).join(' '); const className = data[1] || ''; return cn(['flex items-center gap-2', className])"
}
},
"children": [
{
"id": "breadcrumb-items",
"type": "Fragment",
"_map": {
"source": "items",
"itemVar": "item",
"indexVar": "index"
},
"children": [
{
"id": "breadcrumb-item",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex items-center gap-2'"
}
},
"children": [
{
"id": "breadcrumb-link",
"type": "a",
"bindings": {
"_if": {
"source": "item.href",
"transform": "data"
},
"href": {
"source": "item.href",
"transform": "data || '#'"
},
"onClick": {
"source": "item.onClick",
"transform": "data"
},
"className": {
"source": ["item", "items"],
"transform": "const cn = (classes) => classes.filter(Boolean).join(' '); const item = data[0]; const items = data[1] || []; const isLast = items.indexOf(item) === items.length - 1; const baseClass = 'text-sm transition-colors'; const styleClass = isLast ? 'text-foreground font-medium' : 'text-muted-foreground hover:text-foreground'; return cn([baseClass, styleClass])"
}
},
"children": [
{
"id": "link-text",
"type": "span",
"children": [{"type": "text", "content": {"source": "item.label"}}]
}
]
},
{
"id": "breadcrumb-button",
"type": "button",
"bindings": {
"_if": {
"source": ["item.href", "item.onClick"],
"transform": "!data[0] && data[1]"
},
"onClick": {
"source": "item.onClick",
"transform": "data"
},
"className": {
"source": ["item", "items"],
"transform": "const cn = (classes) => classes.filter(Boolean).join(' '); const item = data[0]; const items = data[1] || []; const isLast = items.indexOf(item) === items.length - 1; const baseClass = 'text-sm transition-colors'; const styleClass = isLast ? 'text-foreground font-medium' : 'text-muted-foreground hover:text-foreground'; return cn([baseClass, styleClass])"
}
},
"children": [
{
"id": "button-text",
"type": "span",
"children": [{"type": "text", "content": {"source": "item.label"}}]
}
]
},
{
"id": "breadcrumb-span",
"type": "span",
"bindings": {
"_if": {
"source": ["item.href", "item.onClick"],
"transform": "!data[0] && !data[1]"
},
"className": {
"source": ["item", "items"],
"transform": "const cn = (classes) => classes.filter(Boolean).join(' '); const item = data[0]; const items = data[1] || []; const isLast = items.indexOf(item) === items.length - 1; const baseClass = 'text-sm'; const styleClass = isLast ? 'text-foreground font-medium' : 'text-muted-foreground'; return cn([baseClass, styleClass])"
}
},
"children": [{"type": "text", "content": {"source": "item.label"}}]
},
{
"id": "separator",
"type": "CaretRight",
"bindings": {
"_if": {
"source": ["item", "items"],
"transform": "const item = data[0]; const items = data[1] || []; return items.indexOf(item) < items.length - 1"
},
"className": {
"source": null,
"transform": "'w-4 h-4 text-muted-foreground'"
}
}
}
]
}
]
}
]
}

View File

@@ -0,0 +1,114 @@
{
"id": "button",
"type": "button",
"bindings": {
"type": {
"source": "type",
"transform": "data || 'button'"
},
"disabled": {
"source": ["disabled", "loading"],
"transform": "data[0] || data[1]"
},
"className": {
"source": ["fullWidth", "className"],
"transform": "const cn = (classes) => classes.filter(Boolean).join(' '); const fullWidth = data[0]; const className = data[1] || ''; const widthClass = fullWidth ? 'w-full' : ''; return cn([widthClass, className])"
},
"onClick": {
"source": "onClick",
"transform": "data"
}
},
"children": [
{
"id": "button-loading-content",
"type": "div",
"bindings": {
"_if": {
"source": "loading",
"transform": "data"
},
"className": {
"source": null,
"transform": "'flex items-center gap-2'"
}
},
"children": [
{
"id": "spinner",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'h-4 w-4 border-2 border-current border-t-transparent rounded-full animate-spin'"
}
}
},
{
"id": "loading-text",
"type": "span",
"children": [
{"type": "text", "content": {"source": "children"}}
]
}
]
},
{
"id": "button-normal-content",
"type": "div",
"bindings": {
"_if": {
"source": "loading",
"transform": "!data"
},
"className": {
"source": null,
"transform": "'flex items-center gap-2'"
}
},
"children": [
{
"id": "left-icon",
"type": "span",
"bindings": {
"_if": {
"source": "leftIcon",
"transform": "data"
},
"className": {
"source": null,
"transform": "'flex-shrink-0'"
}
},
"children": [
{"type": "slot", "source": "leftIcon"}
]
},
{
"id": "button-text",
"type": "span",
"children": [
{"type": "text", "content": {"source": "children"}}
]
},
{
"id": "right-icon",
"type": "span",
"bindings": {
"_if": {
"source": "rightIcon",
"transform": "data"
},
"className": {
"source": null,
"transform": "'flex-shrink-0'"
}
},
"children": [
{"type": "slot", "source": "rightIcon"}
]
}
]
}
]
}

View File

@@ -0,0 +1,26 @@
{
"id": "calendar",
"type": "Calendar",
"bindings": {
"mode": {
"source": "mode",
"transform": "data || 'single'"
},
"selected": {
"source": "selected",
"transform": "data"
},
"onSelect": {
"source": "onSelect",
"transform": "data"
},
"disabled": {
"source": "disabled",
"transform": "data"
},
"className": {
"source": "className",
"transform": "const cn = (classes) => classes.filter(Boolean).join(' '); return cn(['rounded-md border', data || ''])"
}
}
}

View File

@@ -0,0 +1,17 @@
{
"id": "card",
"type": "div",
"bindings": {
"onClick": {
"source": "onClick",
"transform": "data"
},
"className": {
"source": ["variant", "padding", "hover", "onClick", "className"],
"transform": "const cn = (classes) => classes.filter(Boolean).join(' '); const variant = data[0] || 'default'; const padding = data[1] || 'md'; const hover = data[2]; const onClick = data[3]; const className = data[4] || ''; const variantStyles = { default: 'bg-card border border-border', bordered: 'bg-background border-2 border-border', elevated: 'bg-card shadow-lg border border-border', flat: 'bg-muted' }; const paddingStyles = { none: 'p-0', sm: 'p-3', md: 'p-6', lg: 'p-8' }; const hoverClass = (hover || onClick) ? 'hover:shadow-md hover:scale-[1.01] cursor-pointer' : ''; const cursorClass = onClick ? 'cursor-pointer' : ''; return cn(['rounded-lg transition-all', variantStyles[variant], paddingStyles[padding], hoverClass, cursorClass, className])"
}
},
"children": [
{"type": "slot", "source": "children"}
]
}

View File

@@ -0,0 +1,97 @@
{
"id": "checkbox",
"type": "label",
"bindings": {
"className": {
"source": ["disabled", "className"],
"transform": "const cn = (classes) => classes.filter(Boolean).join(' '); const disabled = data[0]; const className = data[1] || ''; const disabledClass = disabled ? 'opacity-50 cursor-not-allowed' : ''; return cn(['flex items-center gap-2 cursor-pointer', disabledClass, className])"
}
},
"children": [
{
"id": "checkbox-button",
"type": "button",
"bindings": {
"type": {
"source": null,
"transform": "'button'"
},
"role": {
"source": null,
"transform": "'checkbox'"
},
"aria-checked": {
"source": ["indeterminate", "checked"],
"transform": "data[0] ? 'mixed' : (data[1] ? 'true' : 'false')"
},
"disabled": {
"source": "disabled",
"transform": "data"
},
"onClick": {
"source": ["disabled", "checked", "onChange"],
"transform": "const disabled = data[0]; const checked = data[1]; const onChange = data[2]; return !disabled ? () => onChange(!checked) : undefined"
},
"className": {
"source": ["size", "checked", "indeterminate"],
"transform": "const cn = (classes) => classes.filter(Boolean).join(' '); const size = data[0] || 'md'; const checked = data[1]; const indeterminate = data[2]; const sizeStyles = { sm: 'w-4 h-4', md: 'w-5 h-5', lg: 'w-6 h-6' }; const stateClass = (checked || indeterminate) ? 'bg-primary border-primary text-primary-foreground' : 'bg-background border-input hover:border-ring'; return cn(['flex items-center justify-center rounded border-2 transition-colors', sizeStyles[size], stateClass])"
}
},
"children": [
{
"id": "indeterminate-icon",
"type": "Minus",
"bindings": {
"_if": {
"source": "indeterminate",
"transform": "data"
},
"size": {
"source": "size",
"transform": "const iconSize = { sm: 12, md: 16, lg: 20 }; return iconSize[data || 'md']"
},
"weight": {
"source": null,
"transform": "'bold'"
}
}
},
{
"id": "check-icon",
"type": "Check",
"bindings": {
"_if": {
"source": ["checked", "indeterminate"],
"transform": "data[0] && !data[1]"
},
"size": {
"source": "size",
"transform": "const iconSize = { sm: 12, md: 16, lg: 20 }; return iconSize[data || 'md']"
},
"weight": {
"source": null,
"transform": "'bold'"
}
}
}
]
},
{
"id": "label-text",
"type": "span",
"bindings": {
"_if": {
"source": "label",
"transform": "data"
},
"className": {
"source": null,
"transform": "'text-sm font-medium select-none'"
}
},
"children": [
{"type": "text", "content": {"source": "label"}}
]
}
]
}

View File

@@ -0,0 +1,236 @@
{
"id": "context-menu",
"type": "ContextMenu",
"bindings": {},
"children": [
{
"id": "trigger",
"type": "ContextMenuTrigger",
"bindings": {
"asChild": {
"source": null,
"transform": "true"
}
},
"children": [
{"type": "slot", "source": "trigger"}
]
},
{
"id": "content",
"type": "ContextMenuContent",
"children": [
{
"id": "menu-items",
"type": "Fragment",
"_map": {
"source": "items",
"itemVar": "item",
"indexVar": "index"
},
"children": [
{
"id": "menu-item",
"type": "ContextMenuSeparator",
"bindings": {
"_if": {
"source": "item.separator",
"transform": "data"
}
}
},
{
"id": "submenu",
"type": "ContextMenuSub",
"bindings": {
"_if": {
"source": ["item.submenu", "item.separator"],
"transform": "data[0] && data[0].length > 0 && !data[1]"
}
},
"children": [
{
"id": "submenu-trigger",
"type": "ContextMenuSubTrigger",
"children": [
{
"id": "submenu-icon",
"type": "span",
"bindings": {
"_if": {
"source": "item.icon",
"transform": "data"
},
"className": {
"source": null,
"transform": "'mr-2'"
}
},
"children": [
{"type": "slot", "source": "item.icon"}
]
},
{
"id": "submenu-label",
"type": "span",
"children": [
{"type": "text", "content": {"source": "item.label"}}
]
}
]
},
{
"id": "submenu-content",
"type": "ContextMenuSubContent",
"children": [
{
"id": "nested-items",
"type": "Fragment",
"_map": {
"source": "item.submenu",
"itemVar": "subitem",
"indexVar": "subindex"
},
"children": [
{
"id": "nested-item",
"type": "ContextMenuItem",
"bindings": {
"onSelect": {
"source": "subitem.onSelect",
"transform": "data"
},
"disabled": {
"source": "subitem.disabled",
"transform": "data"
}
},
"children": [
{
"id": "nested-icon",
"type": "span",
"bindings": {
"_if": {
"source": "subitem.icon",
"transform": "data"
},
"className": {
"source": null,
"transform": "'mr-2'"
}
},
"children": [
{"type": "slot", "source": "subitem.icon"}
]
},
{
"id": "nested-label",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'flex-1'"
}
},
"children": [
{"type": "text", "content": {"source": "subitem.label"}}
]
},
{
"id": "nested-shortcut",
"type": "span",
"bindings": {
"_if": {
"source": "subitem.shortcut",
"transform": "data"
},
"className": {
"source": null,
"transform": "'ml-auto text-xs text-muted-foreground'"
}
},
"children": [
{"type": "text", "content": {"source": "subitem.shortcut"}}
]
}
]
}
]
}
]
}
]
},
{
"id": "regular-item",
"type": "ContextMenuItem",
"bindings": {
"_if": {
"source": ["item.submenu", "item.separator"],
"transform": "(!data[0] || data[0].length === 0) && !data[1]"
},
"onSelect": {
"source": "item.onSelect",
"transform": "data"
},
"disabled": {
"source": "item.disabled",
"transform": "data"
}
},
"children": [
{
"id": "item-icon",
"type": "span",
"bindings": {
"_if": {
"source": "item.icon",
"transform": "data"
},
"className": {
"source": null,
"transform": "'mr-2'"
}
},
"children": [
{"type": "slot", "source": "item.icon"}
]
},
{
"id": "item-label",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'flex-1'"
}
},
"children": [
{"type": "text", "content": {"source": "item.label"}}
]
},
{
"id": "item-shortcut",
"type": "span",
"bindings": {
"_if": {
"source": "item.shortcut",
"transform": "data"
},
"className": {
"source": null,
"transform": "'ml-auto text-xs text-muted-foreground'"
}
},
"children": [
{"type": "text", "content": {"source": "item.shortcut"}}
]
}
]
}
]
}
]
}
]
}

View File

@@ -0,0 +1,12 @@
import { ReactNode } from 'react'
export interface ActionButtonProps {
icon?: ReactNode
label: string
onClick: () => void
variant?: 'default' | 'outline' | 'ghost' | 'destructive'
size?: 'default' | 'sm' | 'lg' | 'icon'
tooltip?: string
disabled?: boolean
className?: string
}

View File

@@ -0,0 +1,10 @@
import { ReactNode } from 'react'
export interface ActionCardProps {
icon?: ReactNode
title: string
description?: string
onClick?: () => void
className?: string
disabled?: boolean
}

View File

@@ -0,0 +1,6 @@
export interface ActionIconProps {
action: 'add' | 'edit' | 'delete' | 'copy' | 'download' | 'upload'
size?: number
weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone'
className?: string
}

View File

@@ -0,0 +1,8 @@
import { ReactNode } from 'react'
export interface AlertProps {
variant?: 'info' | 'warning' | 'success' | 'error'
title?: string
children: ReactNode
className?: string
}

View File

@@ -0,0 +1,3 @@
export interface AppLogoProps {
className?: string
}

View File

@@ -0,0 +1,10 @@
export interface AvatarGroupProps {
avatars: {
src?: string
alt: string
fallback: string
}[]
max?: number
size?: 'xs' | 'sm' | 'md' | 'lg'
className?: string
}

View File

@@ -0,0 +1,7 @@
export interface AvatarProps {
src?: string
alt?: string
fallback?: string
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
className?: string
}

View File

@@ -0,0 +1,9 @@
import { ReactNode } from 'react'
export interface BadgeProps {
children: ReactNode
variant?: 'default' | 'secondary' | 'destructive' | 'outline'
size?: 'sm' | 'md' | 'lg'
icon?: ReactNode
className?: string
}

View File

@@ -0,0 +1,10 @@
export interface BreadcrumbItem {
label: string
href?: string
onClick?: () => void
}
export interface BreadcrumbProps {
items?: BreadcrumbItem[]
className?: string
}

View File

@@ -0,0 +1,15 @@
import { ReactNode } from 'react'
export interface ButtonProps {
children?: ReactNode
leftIcon?: ReactNode
rightIcon?: ReactNode
loading?: boolean
fullWidth?: boolean
disabled?: boolean
className?: string
variant?: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'
size?: 'default' | 'sm' | 'lg' | 'icon'
onClick?: () => void
type?: 'button' | 'submit' | 'reset'
}

View File

@@ -0,0 +1,7 @@
export interface CalendarProps {
selected?: Date
onSelect?: (date: Date | undefined) => void
mode?: 'single' | 'multiple' | 'range'
disabled?: Date | ((date: Date) => boolean)
className?: string
}

View File

@@ -0,0 +1,10 @@
import { ReactNode } from 'react'
export interface CardProps {
children?: ReactNode
variant?: 'default' | 'bordered' | 'elevated' | 'flat'
padding?: 'none' | 'sm' | 'md' | 'lg'
hover?: boolean
className?: string
onClick?: () => void
}

View File

@@ -0,0 +1,9 @@
export interface CheckboxProps {
checked: boolean
onChange: (checked: boolean) => void
label?: string
indeterminate?: boolean
disabled?: boolean
size?: 'sm' | 'md' | 'lg'
className?: string
}

View File

@@ -0,0 +1,16 @@
import { ReactNode } from 'react'
export interface ContextMenuItemType {
label: string
icon?: ReactNode
shortcut?: string
onSelect?: () => void
disabled?: boolean
separator?: boolean
submenu?: ContextMenuItemType[]
}
export interface ContextMenuProps {
trigger: ReactNode
items: ContextMenuItemType[]
}

View File

@@ -29,3 +29,17 @@ export * from './app-main-panel'
export * from './app-dialogs'
export * from './data-source-manager'
export * from './navigation-menu'
export * from './action-button'
export * from './action-card'
export * from './action-icon'
export * from './alert'
export * from './app-logo'
export * from './avatar'
export * from './avatar-group'
export * from './badge'
export * from './breadcrumb'
export * from './button'
export * from './calendar'
export * from './card'
export * from './checkbox'
export * from './context-menu'

View File

@@ -37,6 +37,14 @@ import type {
DataSourceManagerProps,
NavigationMenuProps,
TreeListPanelProps,
ActionButtonProps,
ActionCardProps,
ActionIconProps,
AlertProps,
AppLogoProps,
AvatarProps,
AvatarGroupProps,
BadgeProps,
} from './interfaces'
// Import JSON definitions
@@ -69,6 +77,14 @@ import appDialogsDef from '@/components/json-definitions/app-dialogs.json'
import navigationMenuDef from '@/components/json-definitions/navigation-menu.json'
import dataSourceManagerDef from '@/components/json-definitions/data-source-manager.json'
import treeListPanelDef from '@/components/json-definitions/tree-list-panel.json'
import actionButtonDef from '@/components/json-definitions/action-button.json'
import actionCardDef from '@/components/json-definitions/action-card.json'
import actionIconDef from '@/components/json-definitions/action-icon.json'
import alertDef from '@/components/json-definitions/alert.json'
import appLogoDef from '@/components/json-definitions/app-logo.json'
import avatarDef from '@/components/json-definitions/avatar.json'
import avatarGroupDef from '@/components/json-definitions/avatar-group.json'
import badgeDef from '@/components/json-definitions/badge.json'
// Create pure JSON components (no hooks)
export const LoadingFallback = createJsonComponent<LoadingFallbackProps>(loadingFallbackDef)
@@ -80,6 +96,14 @@ export const GitHubBuildStatus = createJsonComponent<GitHubBuildStatusProps>(git
export const SeedDataManager = createJsonComponent<SeedDataManagerProps>(seedDataManagerDef)
export const TreeCard = createJsonComponent<TreeCardProps>(treeCardDef)
export const AppDialogs = createJsonComponent<AppDialogsProps>(appDialogsDef)
export const ActionButton = createJsonComponent<ActionButtonProps>(actionButtonDef)
export const ActionCard = createJsonComponent<ActionCardProps>(actionCardDef)
export const ActionIcon = createJsonComponent<ActionIconProps>(actionIconDef)
export const Alert = createJsonComponent<AlertProps>(alertDef)
export const AppLogo = createJsonComponent<AppLogoProps>(appLogoDef)
export const Avatar = createJsonComponent<AvatarProps>(avatarDef)
export const AvatarGroup = createJsonComponent<AvatarGroupProps>(avatarGroupDef)
export const Badge = createJsonComponent<BadgeProps>(badgeDef)
// Create JSON components with hooks
export const SaveIndicator = createJsonComponentWithHooks<SaveIndicatorProps>(saveIndicatorDef, {