diff --git a/packages/renderer/src/__tests__/defaultProps.test.tsx b/packages/renderer/src/__tests__/defaultProps.test.tsx
new file mode 100644
index 000000000..4bb03f5d8
--- /dev/null
+++ b/packages/renderer/src/__tests__/defaultProps.test.tsx
@@ -0,0 +1,128 @@
+import { describe, it, expect } from 'vitest';
+import { ComponentRegistry } from '../registry';
+
+// Import all renderers to ensure they're registered
+import '../renderers/basic/div';
+import '../renderers/basic/text';
+import '../renderers/basic/span';
+import '../renderers/basic/separator';
+import '../renderers/form/button';
+import '../renderers/form/input';
+import '../renderers/form/checkbox';
+import '../renderers/form/switch';
+import '../renderers/form/select';
+import '../renderers/form/textarea';
+import '../renderers/form/toggle';
+import '../renderers/form/slider';
+import '../renderers/form/radio-group';
+import '../renderers/form/calendar';
+import '../renderers/form/input-otp';
+import '../renderers/layout/card';
+import '../renderers/layout/tabs';
+import '../renderers/data-display/alert';
+import '../renderers/data-display/avatar';
+import '../renderers/data-display/badge';
+import '../renderers/overlay/dialog';
+import '../renderers/overlay/drawer';
+import '../renderers/overlay/popover';
+import '../renderers/overlay/sheet';
+import '../renderers/overlay/tooltip';
+import '../renderers/overlay/alert-dialog';
+import '../renderers/overlay/dropdown-menu';
+import '../renderers/overlay/context-menu';
+import '../renderers/overlay/hover-card';
+import '../renderers/disclosure/accordion';
+import '../renderers/disclosure/collapsible';
+import '../renderers/complex/table';
+import '../renderers/complex/carousel';
+import '../renderers/complex/resizable';
+import '../renderers/complex/scroll-area';
+import '../renderers/feedback/progress';
+import '../renderers/feedback/skeleton';
+import '../renderers/feedback/toaster';
+
+describe('@object-ui/renderer - Default Props', () => {
+ const componentsRequiringDefaults = [
+ 'div', 'text', 'span', 'separator',
+ 'button', 'input', 'checkbox', 'switch', 'select', 'textarea',
+ 'toggle', 'toggle-group', 'slider', 'radio-group', 'calendar', 'input-otp',
+ 'card', 'tabs',
+ 'alert', 'avatar', 'badge',
+ 'dialog', 'drawer', 'popover', 'sheet', 'tooltip',
+ 'alert-dialog', 'dropdown-menu', 'context-menu', 'hover-card',
+ 'accordion', 'collapsible',
+ 'table', 'carousel', 'resizable', 'scroll-area',
+ 'progress', 'skeleton', 'toaster'
+ ];
+
+ it('should have defaultProps defined for all components', () => {
+ const missingDefaults: string[] = [];
+
+ componentsRequiringDefaults.forEach(type => {
+ const config = ComponentRegistry.getConfig(type);
+ if (!config) {
+ missingDefaults.push(`${type} (not registered)`);
+ } else if (!config.defaultProps && !config.defaultChildren) {
+ missingDefaults.push(`${type} (no defaultProps or defaultChildren)`);
+ }
+ });
+
+ if (missingDefaults.length > 0) {
+ console.error('Components missing default props:', missingDefaults);
+ }
+
+ expect(missingDefaults).toHaveLength(0);
+ });
+
+ it('should have valid defaultProps for button component', () => {
+ const config = ComponentRegistry.getConfig('button');
+ expect(config).toBeDefined();
+ expect(config?.defaultProps).toBeDefined();
+ expect(config?.defaultProps?.label).toBeDefined();
+ expect(typeof config?.defaultProps?.label).toBe('string');
+ });
+
+ it('should have valid defaultProps for input component', () => {
+ const config = ComponentRegistry.getConfig('input');
+ expect(config).toBeDefined();
+ expect(config?.defaultProps).toBeDefined();
+ expect(config?.defaultProps?.label).toBeDefined();
+ expect(config?.defaultProps?.placeholder).toBeDefined();
+ });
+
+ it('should have valid defaultProps for card component', () => {
+ const config = ComponentRegistry.getConfig('card');
+ expect(config).toBeDefined();
+ expect(config?.defaultProps).toBeDefined();
+ expect(config?.defaultProps?.title).toBeDefined();
+ });
+
+ it('should have valid defaultProps for table component', () => {
+ const config = ComponentRegistry.getConfig('table');
+ expect(config).toBeDefined();
+ expect(config?.defaultProps).toBeDefined();
+ expect(config?.defaultProps?.columns).toBeDefined();
+ expect(Array.isArray(config?.defaultProps?.columns)).toBe(true);
+ expect(config?.defaultProps?.data).toBeDefined();
+ expect(Array.isArray(config?.defaultProps?.data)).toBe(true);
+ });
+
+ it('should have valid defaultProps with initial dimensions for div component', () => {
+ const config = ComponentRegistry.getConfig('div');
+ expect(config).toBeDefined();
+ expect(config?.defaultProps).toBeDefined();
+ expect(config?.defaultProps?.className).toBeDefined();
+ // Should have some minimum dimensions to avoid collapsing
+ expect(config?.defaultProps?.className).toContain('min-h');
+ });
+
+ it('should have defaultChildren defined for components that need them', () => {
+ const componentsWithChildren = ['span', 'accordion', 'tabs', 'collapsible'];
+
+ componentsWithChildren.forEach(type => {
+ const config = ComponentRegistry.getConfig(type);
+ expect(config).toBeDefined();
+ expect(config?.defaultChildren || config?.defaultProps).toBeDefined();
+ });
+ });
+});
diff --git a/packages/renderer/src/__tests__/registry.test.tsx b/packages/renderer/src/__tests__/registry.test.tsx
index 68950b17c..0b23271b0 100644
--- a/packages/renderer/src/__tests__/registry.test.tsx
+++ b/packages/renderer/src/__tests__/registry.test.tsx
@@ -97,5 +97,46 @@ describe('@object-ui/renderer - Registry', () => {
consoleWarnSpy.mockRestore();
});
+
+ it('should support defaultProps in component metadata', () => {
+ const TestComponent: ComponentRenderer = ({ schema }) => (
+
{schema.label}
+ );
+
+ ComponentRegistry.register('test-with-defaults', TestComponent, {
+ label: 'Test With Defaults',
+ defaultProps: {
+ label: 'Default Label',
+ variant: 'primary'
+ }
+ });
+
+ const config = ComponentRegistry.getConfig('test-with-defaults');
+ expect(config).toBeDefined();
+ expect(config?.defaultProps).toBeDefined();
+ expect(config?.defaultProps?.label).toBe('Default Label');
+ expect(config?.defaultProps?.variant).toBe('primary');
+ });
+
+ it('should support defaultChildren in component metadata', () => {
+ const TestComponent: ComponentRenderer = ({ schema }) => (
+ {schema.type}
+ );
+
+ ComponentRegistry.register('test-with-children', TestComponent, {
+ label: 'Test With Children',
+ defaultChildren: [
+ { type: 'text', content: 'Child 1' },
+ { type: 'text', content: 'Child 2' }
+ ]
+ });
+
+ const config = ComponentRegistry.getConfig('test-with-children');
+ expect(config).toBeDefined();
+ expect(config?.defaultChildren).toBeDefined();
+ expect(config?.defaultChildren).toHaveLength(2);
+ expect(config?.defaultChildren?.[0].type).toBe('text');
+ expect(config?.defaultChildren?.[0].content).toBe('Child 1');
+ });
});
});
diff --git a/packages/renderer/src/renderers/basic/div.tsx b/packages/renderer/src/renderers/basic/div.tsx
index 0021f85c8..2937c3e35 100644
--- a/packages/renderer/src/renderers/basic/div.tsx
+++ b/packages/renderer/src/renderers/basic/div.tsx
@@ -11,6 +11,9 @@ ComponentRegistry.register('div',
label: 'Container',
inputs: [
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ className: 'p-4 border border-dashed border-gray-300 rounded min-h-[100px]'
+ }
}
);
diff --git a/packages/renderer/src/renderers/basic/separator.tsx b/packages/renderer/src/renderers/basic/separator.tsx
index 455f2f7b8..c8d42a0bb 100644
--- a/packages/renderer/src/renderers/basic/separator.tsx
+++ b/packages/renderer/src/renderers/basic/separator.tsx
@@ -16,6 +16,10 @@ ComponentRegistry.register('separator',
label: 'Orientation'
},
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ orientation: 'horizontal',
+ className: 'my-4'
+ }
}
);
diff --git a/packages/renderer/src/renderers/basic/span.tsx b/packages/renderer/src/renderers/basic/span.tsx
index 41e59a2d3..9b19f1405 100644
--- a/packages/renderer/src/renderers/basic/span.tsx
+++ b/packages/renderer/src/renderers/basic/span.tsx
@@ -11,6 +11,12 @@ ComponentRegistry.register('span',
label: 'Inline Container',
inputs: [
{ name: 'className', type: 'string', label: 'CSS Class' }
+ ],
+ defaultProps: {
+ className: 'px-2 py-1'
+ },
+ defaultChildren: [
+ { type: 'text', content: 'Inline text' }
]
}
);
diff --git a/packages/renderer/src/renderers/basic/text.tsx b/packages/renderer/src/renderers/basic/text.tsx
index 9585d51a5..a842d7641 100644
--- a/packages/renderer/src/renderers/basic/text.tsx
+++ b/packages/renderer/src/renderers/basic/text.tsx
@@ -8,6 +8,9 @@ ComponentRegistry.register('text',
label: 'Text',
inputs: [
{ name: 'content', type: 'string', label: 'Content', required: true }
- ]
+ ],
+ defaultProps: {
+ content: 'Text content'
+ }
}
);
diff --git a/packages/renderer/src/renderers/complex/carousel.tsx b/packages/renderer/src/renderers/complex/carousel.tsx
index dd2e0c710..dc9eea3f7 100644
--- a/packages/renderer/src/renderers/complex/carousel.tsx
+++ b/packages/renderer/src/renderers/complex/carousel.tsx
@@ -44,6 +44,16 @@ ComponentRegistry.register('carousel',
},
{ name: 'itemClassName', type: 'string', label: 'Item CSS Class' },
{ name: 'className', type: 'string', label: 'Container CSS Class' }
- ]
+ ],
+ defaultProps: {
+ orientation: 'horizontal',
+ showArrows: true,
+ items: [
+ [{ type: 'div', className: 'p-8 border rounded bg-slate-50', body: [{ type: 'text', content: 'Slide 1' }] }],
+ [{ type: 'div', className: 'p-8 border rounded bg-slate-50', body: [{ type: 'text', content: 'Slide 2' }] }],
+ [{ type: 'div', className: 'p-8 border rounded bg-slate-50', body: [{ type: 'text', content: 'Slide 3' }] }]
+ ],
+ className: 'w-full max-w-xs'
+ }
}
);
diff --git a/packages/renderer/src/renderers/complex/resizable.tsx b/packages/renderer/src/renderers/complex/resizable.tsx
index 63691b99d..af1759692 100644
--- a/packages/renderer/src/renderers/complex/resizable.tsx
+++ b/packages/renderer/src/renderers/complex/resizable.tsx
@@ -38,6 +38,16 @@ ComponentRegistry.register('resizable',
description: 'Array of { defaultSize, minSize, maxSize, content }'
},
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ direction: 'horizontal',
+ minHeight: '200px',
+ withHandle: true,
+ panels: [
+ { defaultSize: 50, content: [{ type: 'div', className: 'p-4', body: [{ type: 'text', content: 'Panel 1' }] }] },
+ { defaultSize: 50, content: [{ type: 'div', className: 'p-4', body: [{ type: 'text', content: 'Panel 2' }] }] }
+ ],
+ className: 'rounded-lg border'
+ }
}
);
diff --git a/packages/renderer/src/renderers/complex/scroll-area.tsx b/packages/renderer/src/renderers/complex/scroll-area.tsx
index b2aadda67..14e507e13 100644
--- a/packages/renderer/src/renderers/complex/scroll-area.tsx
+++ b/packages/renderer/src/renderers/complex/scroll-area.tsx
@@ -17,6 +17,15 @@ ComponentRegistry.register('scroll-area',
{ name: 'orientation', type: 'enum', enum: ['vertical', 'horizontal', 'both'], defaultValue: 'vertical', label: 'Orientation' },
{ name: 'content', type: 'slot', label: 'Content' },
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ height: '200px',
+ width: '100%',
+ orientation: 'vertical',
+ content: [
+ { type: 'div', className: 'p-4', body: [{ type: 'text', content: 'Scrollable content goes here. Add more content to see scrolling behavior.' }] }
+ ],
+ className: 'rounded-md border'
+ }
}
);
diff --git a/packages/renderer/src/renderers/complex/table.tsx b/packages/renderer/src/renderers/complex/table.tsx
index 5405b52a7..8c7822cbd 100644
--- a/packages/renderer/src/renderers/complex/table.tsx
+++ b/packages/renderer/src/renderers/complex/table.tsx
@@ -63,6 +63,19 @@ ComponentRegistry.register('table',
description: 'Array of objects'
},
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ caption: 'Table Caption',
+ columns: [
+ { header: 'Column 1', accessorKey: 'col1' },
+ { header: 'Column 2', accessorKey: 'col2' },
+ { header: 'Column 3', accessorKey: 'col3' }
+ ],
+ data: [
+ { col1: 'Row 1, Col 1', col2: 'Row 1, Col 2', col3: 'Row 1, Col 3' },
+ { col1: 'Row 2, Col 1', col2: 'Row 2, Col 2', col3: 'Row 2, Col 3' },
+ { col1: 'Row 3, Col 1', col2: 'Row 3, Col 2', col3: 'Row 3, Col 3' }
+ ]
+ }
}
);
diff --git a/packages/renderer/src/renderers/data-display/alert.tsx b/packages/renderer/src/renderers/data-display/alert.tsx
index 5710b9432..8d52a2a9e 100644
--- a/packages/renderer/src/renderers/data-display/alert.tsx
+++ b/packages/renderer/src/renderers/data-display/alert.tsx
@@ -26,6 +26,11 @@ ComponentRegistry.register('alert',
label: 'Variant'
},
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ title: 'Alert Title',
+ description: 'This is an alert message.',
+ variant: 'default'
+ }
}
);
diff --git a/packages/renderer/src/renderers/data-display/avatar.tsx b/packages/renderer/src/renderers/data-display/avatar.tsx
index d1e21d53b..65b4edc6e 100644
--- a/packages/renderer/src/renderers/data-display/avatar.tsx
+++ b/packages/renderer/src/renderers/data-display/avatar.tsx
@@ -19,6 +19,10 @@ ComponentRegistry.register('avatar',
{ name: 'alt', type: 'string', label: 'Alt Text' },
{ name: 'fallback', type: 'string', label: 'Fallback Initials', defaultValue: 'CN' },
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ fallback: 'CN',
+ alt: 'Avatar'
+ }
}
);
diff --git a/packages/renderer/src/renderers/data-display/badge.tsx b/packages/renderer/src/renderers/data-display/badge.tsx
index b422f1675..1b713725e 100644
--- a/packages/renderer/src/renderers/data-display/badge.tsx
+++ b/packages/renderer/src/renderers/data-display/badge.tsx
@@ -20,6 +20,10 @@ ComponentRegistry.register('badge',
label: 'Variant'
},
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ label: 'Badge',
+ variant: 'default'
+ }
}
);
diff --git a/packages/renderer/src/renderers/disclosure/accordion.tsx b/packages/renderer/src/renderers/disclosure/accordion.tsx
index 28267f0d7..bf4344e80 100644
--- a/packages/renderer/src/renderers/disclosure/accordion.tsx
+++ b/packages/renderer/src/renderers/disclosure/accordion.tsx
@@ -32,6 +32,28 @@ ComponentRegistry.register('accordion',
description: 'Array of { trigger, content, value }'
},
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ accordionType: 'single',
+ collapsible: true,
+ items: [
+ {
+ label: 'Item 1',
+ value: 'item-1',
+ content: [{ type: 'text', content: 'Content for item 1' }]
+ },
+ {
+ label: 'Item 2',
+ value: 'item-2',
+ content: [{ type: 'text', content: 'Content for item 2' }]
+ },
+ {
+ label: 'Item 3',
+ value: 'item-3',
+ content: [{ type: 'text', content: 'Content for item 3' }]
+ }
+ ],
+ className: 'w-full'
+ }
}
);
diff --git a/packages/renderer/src/renderers/disclosure/collapsible.tsx b/packages/renderer/src/renderers/disclosure/collapsible.tsx
index 19f00616d..9d5d79f76 100644
--- a/packages/renderer/src/renderers/disclosure/collapsible.tsx
+++ b/packages/renderer/src/renderers/disclosure/collapsible.tsx
@@ -33,6 +33,11 @@ ComponentRegistry.register('collapsible',
label: 'Content'
},
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ trigger: [{ type: 'button', label: 'Toggle', variant: 'outline' }],
+ content: [{ type: 'text', content: 'Collapsible content goes here' }],
+ className: 'w-full'
+ }
}
);
diff --git a/packages/renderer/src/renderers/feedback/progress.tsx b/packages/renderer/src/renderers/feedback/progress.tsx
index 51d8303d5..61b320940 100644
--- a/packages/renderer/src/renderers/feedback/progress.tsx
+++ b/packages/renderer/src/renderers/feedback/progress.tsx
@@ -10,6 +10,10 @@ ComponentRegistry.register('progress',
inputs: [
{ name: 'value', type: 'number', label: 'Value', defaultValue: 0 },
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ value: 50,
+ className: 'w-full'
+ }
}
);
diff --git a/packages/renderer/src/renderers/feedback/skeleton.tsx b/packages/renderer/src/renderers/feedback/skeleton.tsx
index f8a3d898d..ce0baa416 100644
--- a/packages/renderer/src/renderers/feedback/skeleton.tsx
+++ b/packages/renderer/src/renderers/feedback/skeleton.tsx
@@ -11,6 +11,11 @@ ComponentRegistry.register('skeleton',
{ name: 'width', type: 'string', label: 'Width' },
{ name: 'height', type: 'string', label: 'Height' },
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ width: '100%',
+ height: '20px',
+ className: 'rounded-md'
+ }
}
);
diff --git a/packages/renderer/src/renderers/feedback/toaster.tsx b/packages/renderer/src/renderers/feedback/toaster.tsx
index 2c2ee67bb..4b3e20002 100644
--- a/packages/renderer/src/renderers/feedback/toaster.tsx
+++ b/packages/renderer/src/renderers/feedback/toaster.tsx
@@ -17,6 +17,9 @@ ComponentRegistry.register('toaster',
label: 'Toaster',
inputs: [
{ name: 'provider', type: 'enum', enum: ['default', 'sonner'], defaultValue: 'default', label: 'Provider' }
- ]
+ ],
+ defaultProps: {
+ provider: 'default'
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/button.tsx b/packages/renderer/src/renderers/form/button.tsx
index 417dd158f..5435eb897 100644
--- a/packages/renderer/src/renderers/form/button.tsx
+++ b/packages/renderer/src/renderers/form/button.tsx
@@ -27,6 +27,11 @@ ComponentRegistry.register('button',
defaultValue: 'default'
},
{ name: 'className', type: 'string', label: 'CSS Class', advanced: true }
- ]
+ ],
+ defaultProps: {
+ label: 'Button',
+ variant: 'default',
+ size: 'default'
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/calendar.tsx b/packages/renderer/src/renderers/form/calendar.tsx
index 985fabca6..1e9372c9e 100644
--- a/packages/renderer/src/renderers/form/calendar.tsx
+++ b/packages/renderer/src/renderers/form/calendar.tsx
@@ -15,6 +15,10 @@ ComponentRegistry.register('calendar',
inputs: [
{ name: 'mode', type: 'enum', enum: ['default', 'single', 'multiple', 'range'], defaultValue: 'single', label: 'Mode' },
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ mode: 'single',
+ className: 'rounded-md border'
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/checkbox.tsx b/packages/renderer/src/renderers/form/checkbox.tsx
index 4a96498f3..bf2dc6e74 100644
--- a/packages/renderer/src/renderers/form/checkbox.tsx
+++ b/packages/renderer/src/renderers/form/checkbox.tsx
@@ -16,6 +16,10 @@ ComponentRegistry.register('checkbox',
{ name: 'label', type: 'string', label: 'Label', required: true },
{ name: 'id', type: 'string', label: 'ID', required: true },
{ name: 'checked', type: 'boolean', label: 'Checked' }
- ]
+ ],
+ defaultProps: {
+ label: 'Checkbox label',
+ id: 'checkbox-field' // Will be made unique by designer's ensureNodeIds
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/input-otp.tsx b/packages/renderer/src/renderers/form/input-otp.tsx
index 0c0d5930c..fbfb2e48b 100644
--- a/packages/renderer/src/renderers/form/input-otp.tsx
+++ b/packages/renderer/src/renderers/form/input-otp.tsx
@@ -22,6 +22,9 @@ ComponentRegistry.register('input-otp',
inputs: [
{ name: 'maxLength', type: 'number', label: 'Max Length', defaultValue: 6 },
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ maxLength: 6
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/input.tsx b/packages/renderer/src/renderers/form/input.tsx
index 861c8c7e4..3aae4b421 100644
--- a/packages/renderer/src/renderers/form/input.tsx
+++ b/packages/renderer/src/renderers/form/input.tsx
@@ -27,6 +27,12 @@ ComponentRegistry.register('input',
defaultValue: 'text'
},
{ name: 'id', type: 'string', label: 'ID', required: true }
- ]
+ ],
+ defaultProps: {
+ label: 'Label',
+ placeholder: 'Enter text...',
+ inputType: 'text',
+ id: 'input-field' // Will be made unique by designer's ensureNodeIds
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/radio-group.tsx b/packages/renderer/src/renderers/form/radio-group.tsx
index 19b61fcaf..ba4536f76 100644
--- a/packages/renderer/src/renderers/form/radio-group.tsx
+++ b/packages/renderer/src/renderers/form/radio-group.tsx
@@ -24,6 +24,14 @@ ComponentRegistry.register('radio-group',
description: 'Array of {label, value} objects'
},
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ id: 'radio-group', // Will be made unique by designer's ensureNodeIds
+ items: [
+ { label: 'Option 1', value: 'option1' },
+ { label: 'Option 2', value: 'option2' },
+ { label: 'Option 3', value: 'option3' }
+ ]
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/select.tsx b/packages/renderer/src/renderers/form/select.tsx
index 1eba9a22d..5b7b037db 100644
--- a/packages/renderer/src/renderers/form/select.tsx
+++ b/packages/renderer/src/renderers/form/select.tsx
@@ -36,6 +36,15 @@ ComponentRegistry.register('select',
label: 'Options',
description: 'Array of {label, value} objects'
}
- ]
+ ],
+ defaultProps: {
+ label: 'Select an option',
+ placeholder: 'Choose...',
+ options: [
+ { label: 'Option 1', value: 'option1' },
+ { label: 'Option 2', value: 'option2' },
+ { label: 'Option 3', value: 'option3' }
+ ]
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/slider.tsx b/packages/renderer/src/renderers/form/slider.tsx
index a335b2a4b..2f93e5657 100644
--- a/packages/renderer/src/renderers/form/slider.tsx
+++ b/packages/renderer/src/renderers/form/slider.tsx
@@ -20,6 +20,13 @@ ComponentRegistry.register('slider',
{ name: 'min', type: 'number', label: 'Min', defaultValue: 0 },
{ name: 'step', type: 'number', label: 'Step', defaultValue: 1 },
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ defaultValue: [50],
+ max: 100,
+ min: 0,
+ step: 1,
+ className: 'w-full'
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/switch.tsx b/packages/renderer/src/renderers/form/switch.tsx
index e33710100..28b073462 100644
--- a/packages/renderer/src/renderers/form/switch.tsx
+++ b/packages/renderer/src/renderers/form/switch.tsx
@@ -14,6 +14,10 @@ ComponentRegistry.register('switch',
{ name: 'label', type: 'string', label: 'Label', required: true },
{ name: 'id', type: 'string', label: 'ID', required: true },
{ name: 'checked', type: 'boolean', label: 'Checked' }
- ]
+ ],
+ defaultProps: {
+ label: 'Switch label',
+ id: 'switch-field' // Will be made unique by designer's ensureNodeIds
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/textarea.tsx b/packages/renderer/src/renderers/form/textarea.tsx
index 982b5ed85..b5fe251e3 100644
--- a/packages/renderer/src/renderers/form/textarea.tsx
+++ b/packages/renderer/src/renderers/form/textarea.tsx
@@ -19,6 +19,11 @@ ComponentRegistry.register('textarea',
{ name: 'label', type: 'string', label: 'Label' },
{ name: 'placeholder', type: 'string', label: 'Placeholder' },
{ name: 'id', type: 'string', label: 'ID', required: true }
- ]
+ ],
+ defaultProps: {
+ label: 'Textarea label',
+ placeholder: 'Enter text here...',
+ id: 'textarea-field' // Will be made unique by designer's ensureNodeIds
+ }
}
);
diff --git a/packages/renderer/src/renderers/form/toggle.tsx b/packages/renderer/src/renderers/form/toggle.tsx
index c54e8e349..6d0d963fe 100644
--- a/packages/renderer/src/renderers/form/toggle.tsx
+++ b/packages/renderer/src/renderers/form/toggle.tsx
@@ -22,7 +22,12 @@ ComponentRegistry.register('toggle',
{ name: 'variant', type: 'enum', enum: ['default', 'outline'], defaultValue: 'default', label: 'Variant' },
{ name: 'size', type: 'enum', enum: ['default', 'sm', 'lg'], defaultValue: 'default', label: 'Size' },
{ name: 'ariaLabel', type: 'string', label: 'Aria Label' }
- ]
+ ],
+ defaultProps: {
+ label: 'Toggle',
+ variant: 'default',
+ size: 'default'
+ }
}
);
@@ -55,6 +60,16 @@ ComponentRegistry.register('toggle-group',
description: 'Array of {label, value, icon?} objects'
},
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ groupType: 'single',
+ variant: 'default',
+ size: 'default',
+ items: [
+ { label: 'A', value: 'a' },
+ { label: 'B', value: 'b' },
+ { label: 'C', value: 'c' }
+ ]
+ }
}
);
diff --git a/packages/renderer/src/renderers/layout/card.tsx b/packages/renderer/src/renderers/layout/card.tsx
index 1873d9fca..1ad11a454 100644
--- a/packages/renderer/src/renderers/layout/card.tsx
+++ b/packages/renderer/src/renderers/layout/card.tsx
@@ -28,6 +28,11 @@ ComponentRegistry.register('card',
{ name: 'title', type: 'string', label: 'Title' },
{ name: 'description', type: 'string', label: 'Description' },
{ name: 'className', type: 'string', label: 'CSS Class' }
- ]
+ ],
+ defaultProps: {
+ title: 'Card Title',
+ description: 'Card description goes here',
+ className: 'w-full'
+ }
}
);
diff --git a/packages/renderer/src/renderers/layout/tabs.tsx b/packages/renderer/src/renderers/layout/tabs.tsx
index 7d31d2e92..3e7d702a0 100644
--- a/packages/renderer/src/renderers/layout/tabs.tsx
+++ b/packages/renderer/src/renderers/layout/tabs.tsx
@@ -32,6 +32,15 @@ ComponentRegistry.register('tabs',
type: 'array',
label: 'Items'
}
- ]
+ ],
+ defaultProps: {
+ defaultValue: 'tab1',
+ items: [
+ { label: 'Tab 1', value: 'tab1', body: [{ type: 'text', content: 'Content for Tab 1' }] },
+ { label: 'Tab 2', value: 'tab2', body: [{ type: 'text', content: 'Content for Tab 2' }] },
+ { label: 'Tab 3', value: 'tab3', body: [{ type: 'text', content: 'Content for Tab 3' }] }
+ ],
+ className: 'w-full'
+ }
}
);
diff --git a/packages/renderer/src/renderers/navigation/header-bar.tsx b/packages/renderer/src/renderers/navigation/header-bar.tsx
index 0593e5be2..5a2a998af 100644
--- a/packages/renderer/src/renderers/navigation/header-bar.tsx
+++ b/packages/renderer/src/renderers/navigation/header-bar.tsx
@@ -38,6 +38,12 @@ ComponentRegistry.register('header-bar',
label: 'Header Bar',
inputs: [
{ name: 'crumbs', type: 'array', label: 'Breadcrumbs' }
- ]
+ ],
+ defaultProps: {
+ crumbs: [
+ { label: 'Home', href: '#' },
+ { label: 'Current Page' }
+ ]
+ }
}
);
diff --git a/packages/renderer/src/renderers/navigation/sidebar.tsx b/packages/renderer/src/renderers/navigation/sidebar.tsx
index a0b88c212..8103a8512 100644
--- a/packages/renderer/src/renderers/navigation/sidebar.tsx
+++ b/packages/renderer/src/renderers/navigation/sidebar.tsx
@@ -24,6 +24,13 @@ ComponentRegistry.register('sidebar-provider',
label: 'Sidebar Provider',
inputs: [
{ name: 'defaultOpen', type: 'boolean', label: 'Default Open', defaultValue: true }
+ ],
+ defaultProps: {
+ defaultOpen: true
+ },
+ defaultChildren: [
+ { type: 'sidebar' },
+ { type: 'sidebar-inset' }
]
}
);
@@ -38,6 +45,16 @@ ComponentRegistry.register('sidebar',
{ name: 'collapsible', type: 'enum', enum: ['offcanvas', 'icon', 'none'], defaultValue: 'icon', label: 'Collapsible' },
{ name: 'side', type: 'enum', enum: ['left', 'right'], defaultValue: 'left', label: 'Side' },
{ name: 'variant', type: 'enum', enum: ['sidebar', 'floating', 'inset'], defaultValue: 'sidebar', label: 'Variant' }
+ ],
+ defaultProps: {
+ collapsible: 'icon',
+ side: 'left',
+ variant: 'sidebar'
+ },
+ defaultChildren: [
+ { type: 'sidebar-header' },
+ { type: 'sidebar-content' },
+ { type: 'sidebar-footer' }
]
}
);
@@ -46,14 +63,24 @@ ComponentRegistry.register('sidebar-header',
({ schema, ...props }) => (
{renderChildren(schema.body)}
),
- { label: 'Sidebar Header' }
+ {
+ label: 'Sidebar Header',
+ defaultChildren: [
+ { type: 'text', content: 'Sidebar Header' }
+ ]
+ }
);
ComponentRegistry.register('sidebar-content',
({ schema, ...props }) => (
{renderChildren(schema.body)}
),
- { label: 'Sidebar Content' }
+ {
+ label: 'Sidebar Content',
+ defaultChildren: [
+ { type: 'sidebar-group' }
+ ]
+ }
);
ComponentRegistry.register('sidebar-group',
@@ -69,6 +96,12 @@ ComponentRegistry.register('sidebar-group',
label: 'Sidebar Group',
inputs: [
{ name: 'label', type: 'string', label: 'Label' }
+ ],
+ defaultProps: {
+ label: 'Menu'
+ },
+ defaultChildren: [
+ { type: 'sidebar-menu' }
]
}
);
@@ -77,14 +110,25 @@ ComponentRegistry.register('sidebar-menu',
({ schema, ...props }) => (
{renderChildren(schema.body)}
),
- { label: 'Sidebar Menu' }
+ {
+ label: 'Sidebar Menu',
+ defaultChildren: [
+ { type: 'sidebar-menu-item' },
+ { type: 'sidebar-menu-item' }
+ ]
+ }
);
ComponentRegistry.register('sidebar-menu-item',
({ schema, ...props }) => (
{renderChildren(schema.body)}
),
- { label: 'Sidebar Menu Item' }
+ {
+ label: 'Sidebar Menu Item',
+ defaultChildren: [
+ { type: 'sidebar-menu-button' }
+ ]
+ }
);
ComponentRegistry.register('sidebar-menu-button',
@@ -99,6 +143,12 @@ ComponentRegistry.register('sidebar-menu-button',
{ name: 'active', type: 'boolean', label: 'Active', defaultValue: false },
{ name: 'size', type: 'enum', enum: ['default', 'sm', 'lg'], defaultValue: 'default', label: 'Size' },
{ name: 'tooltip', type: 'string', label: 'Tooltip' }
+ ],
+ defaultProps: {
+ size: 'default'
+ },
+ defaultChildren: [
+ { type: 'text', content: 'Menu Item' }
]
}
);
@@ -107,14 +157,24 @@ ComponentRegistry.register('sidebar-footer',
({ schema, ...props }) => (
{renderChildren(schema.body)}
),
- { label: 'Sidebar Footer' }
+ {
+ label: 'Sidebar Footer',
+ defaultChildren: [
+ { type: 'text', content: 'Footer' }
+ ]
+ }
);
ComponentRegistry.register('sidebar-inset',
({ schema, ...props }) => (
{renderChildren(schema.body)}
),
- { label: 'Sidebar Inset' }
+ {
+ label: 'Sidebar Inset',
+ defaultChildren: [
+ { type: 'div', className: 'p-4', body: [{ type: 'text', content: 'Main content area' }] }
+ ]
+ }
);
ComponentRegistry.register('sidebar-trigger',
diff --git a/packages/renderer/src/renderers/overlay/alert-dialog.tsx b/packages/renderer/src/renderers/overlay/alert-dialog.tsx
index 8bbce43d2..9f6347a85 100644
--- a/packages/renderer/src/renderers/overlay/alert-dialog.tsx
+++ b/packages/renderer/src/renderers/overlay/alert-dialog.tsx
@@ -50,6 +50,13 @@ ComponentRegistry.register('alert-dialog',
label: 'Content/Body'
},
{ name: 'className', type: 'string', label: 'Content CSS Class' }
- ]
+ ],
+ defaultProps: {
+ title: 'Are you sure?',
+ description: 'This action cannot be undone.',
+ cancelText: 'Cancel',
+ actionText: 'Continue',
+ trigger: [{ type: 'button', label: 'Open Alert', variant: 'destructive' }]
+ }
}
);
diff --git a/packages/renderer/src/renderers/overlay/context-menu.tsx b/packages/renderer/src/renderers/overlay/context-menu.tsx
index 397f9bd89..17ce8572c 100644
--- a/packages/renderer/src/renderers/overlay/context-menu.tsx
+++ b/packages/renderer/src/renderers/overlay/context-menu.tsx
@@ -71,6 +71,15 @@ ComponentRegistry.register('context-menu',
description: 'Recursive structure: { type?: "separator"|"label", label, shortcut, children }'
},
{ name: 'className', type: 'string', label: 'Content CSS Class' }
- ]
+ ],
+ defaultProps: {
+ items: [
+ { label: 'Action 1' },
+ { label: 'Action 2' },
+ { type: 'separator' },
+ { label: 'Action 3' }
+ ],
+ trigger: [{ type: 'text', content: 'Right click here' }]
+ }
}
);
diff --git a/packages/renderer/src/renderers/overlay/dialog.tsx b/packages/renderer/src/renderers/overlay/dialog.tsx
index 3d88105fe..0402f7833 100644
--- a/packages/renderer/src/renderers/overlay/dialog.tsx
+++ b/packages/renderer/src/renderers/overlay/dialog.tsx
@@ -55,6 +55,13 @@ ComponentRegistry.register('dialog',
label: 'Footer'
},
{ name: 'className', type: 'string', label: 'Content CSS Class' }
- ]
+ ],
+ defaultProps: {
+ title: 'Dialog Title',
+ description: 'Dialog description goes here',
+ modal: true,
+ trigger: [{ type: 'button', label: 'Open Dialog' }],
+ content: [{ type: 'text', content: 'Dialog content goes here' }]
+ }
}
);
diff --git a/packages/renderer/src/renderers/overlay/drawer.tsx b/packages/renderer/src/renderers/overlay/drawer.tsx
index accc5d468..2fb28b724 100644
--- a/packages/renderer/src/renderers/overlay/drawer.tsx
+++ b/packages/renderer/src/renderers/overlay/drawer.tsx
@@ -56,6 +56,12 @@ ComponentRegistry.register('drawer',
label: 'Footer'
},
{ name: 'className', type: 'string', label: 'Content CSS Class' }
- ]
+ ],
+ defaultProps: {
+ title: 'Drawer Title',
+ description: 'Drawer description',
+ trigger: [{ type: 'button', label: 'Open Drawer' }],
+ content: [{ type: 'text', content: 'Drawer content goes here' }]
+ }
}
);
diff --git a/packages/renderer/src/renderers/overlay/dropdown-menu.tsx b/packages/renderer/src/renderers/overlay/dropdown-menu.tsx
index b76787c57..26b28ae07 100644
--- a/packages/renderer/src/renderers/overlay/dropdown-menu.tsx
+++ b/packages/renderer/src/renderers/overlay/dropdown-menu.tsx
@@ -73,6 +73,17 @@ ComponentRegistry.register('dropdown-menu',
description: 'Recursive structure: { type?: "separator"|"label", label, icon, shortcut, disabled, children: [] }'
},
{ name: 'className', type: 'string', label: 'Content CSS Class' }
- ]
+ ],
+ defaultProps: {
+ trigger: [{ type: 'button', label: 'Menu', variant: 'outline' }],
+ items: [
+ { label: 'Item 1' },
+ { label: 'Item 2' },
+ { type: 'separator' },
+ { label: 'Item 3' }
+ ],
+ align: 'start',
+ side: 'bottom'
+ }
}
);
diff --git a/packages/renderer/src/renderers/overlay/hover-card.tsx b/packages/renderer/src/renderers/overlay/hover-card.tsx
index b79cf5b87..fd227298f 100644
--- a/packages/renderer/src/renderers/overlay/hover-card.tsx
+++ b/packages/renderer/src/renderers/overlay/hover-card.tsx
@@ -35,6 +35,11 @@ ComponentRegistry.register('hover-card',
label: 'Content'
},
{ name: 'className', type: 'string', label: 'Content CSS Class' }
- ]
+ ],
+ defaultProps: {
+ trigger: [{ type: 'button', label: 'Hover me', variant: 'link' }],
+ content: [{ type: 'text', content: 'Hover card content appears on hover' }],
+ side: 'top'
+ }
}
);
diff --git a/packages/renderer/src/renderers/overlay/popover.tsx b/packages/renderer/src/renderers/overlay/popover.tsx
index 3425150b9..0bf032ba7 100644
--- a/packages/renderer/src/renderers/overlay/popover.tsx
+++ b/packages/renderer/src/renderers/overlay/popover.tsx
@@ -35,6 +35,12 @@ ComponentRegistry.register('popover',
label: 'Content',
},
{ name: 'className', type: 'string', label: 'Content CSS Class' }
- ]
+ ],
+ defaultProps: {
+ trigger: [{ type: 'button', label: 'Open Popover', variant: 'outline' }],
+ content: [{ type: 'text', content: 'Popover content goes here' }],
+ align: 'center',
+ side: 'bottom'
+ }
}
);
diff --git a/packages/renderer/src/renderers/overlay/sheet.tsx b/packages/renderer/src/renderers/overlay/sheet.tsx
index a534276fd..6aa11de6f 100644
--- a/packages/renderer/src/renderers/overlay/sheet.tsx
+++ b/packages/renderer/src/renderers/overlay/sheet.tsx
@@ -54,6 +54,14 @@ ComponentRegistry.register('sheet',
label: 'Footer'
},
{ name: 'className', type: 'string', label: 'Content CSS Class' }
- ]
+ ],
+ defaultProps: {
+ title: 'Sheet Title',
+ description: 'Sheet description',
+ side: 'right',
+ modal: true,
+ trigger: [{ type: 'button', label: 'Open Sheet' }],
+ content: [{ type: 'text', content: 'Sheet content goes here' }]
+ }
}
);
diff --git a/packages/renderer/src/renderers/overlay/tooltip.tsx b/packages/renderer/src/renderers/overlay/tooltip.tsx
index 1308181ed..4d3dd9bf1 100644
--- a/packages/renderer/src/renderers/overlay/tooltip.tsx
+++ b/packages/renderer/src/renderers/overlay/tooltip.tsx
@@ -46,6 +46,12 @@ ComponentRegistry.register('tooltip',
label: 'Rich Content'
},
{ name: 'className', type: 'string', label: 'Content CSS Class' }
- ]
+ ],
+ defaultProps: {
+ trigger: [{ type: 'button', label: 'Hover me', variant: 'outline' }],
+ content: 'Tooltip content',
+ delayDuration: 700,
+ side: 'top'
+ }
}
);