Skip to content

Commit 0c94c51

Browse files
authored
Merge pull request #4 from objectql/copilot/add-initial-state-to-components
2 parents 659eb14 + b4af140 commit 0c94c51

42 files changed

Lines changed: 539 additions & 45 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { ComponentRegistry } from '../registry';
3+
4+
// Import all renderers to ensure they're registered
5+
import '../renderers/basic/div';
6+
import '../renderers/basic/text';
7+
import '../renderers/basic/span';
8+
import '../renderers/basic/separator';
9+
import '../renderers/form/button';
10+
import '../renderers/form/input';
11+
import '../renderers/form/checkbox';
12+
import '../renderers/form/switch';
13+
import '../renderers/form/select';
14+
import '../renderers/form/textarea';
15+
import '../renderers/form/toggle';
16+
import '../renderers/form/slider';
17+
import '../renderers/form/radio-group';
18+
import '../renderers/form/calendar';
19+
import '../renderers/form/input-otp';
20+
import '../renderers/layout/card';
21+
import '../renderers/layout/tabs';
22+
import '../renderers/data-display/alert';
23+
import '../renderers/data-display/avatar';
24+
import '../renderers/data-display/badge';
25+
import '../renderers/overlay/dialog';
26+
import '../renderers/overlay/drawer';
27+
import '../renderers/overlay/popover';
28+
import '../renderers/overlay/sheet';
29+
import '../renderers/overlay/tooltip';
30+
import '../renderers/overlay/alert-dialog';
31+
import '../renderers/overlay/dropdown-menu';
32+
import '../renderers/overlay/context-menu';
33+
import '../renderers/overlay/hover-card';
34+
import '../renderers/disclosure/accordion';
35+
import '../renderers/disclosure/collapsible';
36+
import '../renderers/complex/table';
37+
import '../renderers/complex/carousel';
38+
import '../renderers/complex/resizable';
39+
import '../renderers/complex/scroll-area';
40+
import '../renderers/feedback/progress';
41+
import '../renderers/feedback/skeleton';
42+
import '../renderers/feedback/toaster';
43+
44+
describe('@object-ui/renderer - Default Props', () => {
45+
const componentsRequiringDefaults = [
46+
'div', 'text', 'span', 'separator',
47+
'button', 'input', 'checkbox', 'switch', 'select', 'textarea',
48+
'toggle', 'toggle-group', 'slider', 'radio-group', 'calendar', 'input-otp',
49+
'card', 'tabs',
50+
'alert', 'avatar', 'badge',
51+
'dialog', 'drawer', 'popover', 'sheet', 'tooltip',
52+
'alert-dialog', 'dropdown-menu', 'context-menu', 'hover-card',
53+
'accordion', 'collapsible',
54+
'table', 'carousel', 'resizable', 'scroll-area',
55+
'progress', 'skeleton', 'toaster'
56+
];
57+
58+
it('should have defaultProps defined for all components', () => {
59+
const missingDefaults: string[] = [];
60+
61+
componentsRequiringDefaults.forEach(type => {
62+
const config = ComponentRegistry.getConfig(type);
63+
if (!config) {
64+
missingDefaults.push(`${type} (not registered)`);
65+
} else if (!config.defaultProps && !config.defaultChildren) {
66+
missingDefaults.push(`${type} (no defaultProps or defaultChildren)`);
67+
}
68+
});
69+
70+
if (missingDefaults.length > 0) {
71+
console.error('Components missing default props:', missingDefaults);
72+
}
73+
74+
expect(missingDefaults).toHaveLength(0);
75+
});
76+
77+
it('should have valid defaultProps for button component', () => {
78+
const config = ComponentRegistry.getConfig('button');
79+
expect(config).toBeDefined();
80+
expect(config?.defaultProps).toBeDefined();
81+
expect(config?.defaultProps?.label).toBeDefined();
82+
expect(typeof config?.defaultProps?.label).toBe('string');
83+
});
84+
85+
it('should have valid defaultProps for input component', () => {
86+
const config = ComponentRegistry.getConfig('input');
87+
expect(config).toBeDefined();
88+
expect(config?.defaultProps).toBeDefined();
89+
expect(config?.defaultProps?.label).toBeDefined();
90+
expect(config?.defaultProps?.placeholder).toBeDefined();
91+
});
92+
93+
it('should have valid defaultProps for card component', () => {
94+
const config = ComponentRegistry.getConfig('card');
95+
expect(config).toBeDefined();
96+
expect(config?.defaultProps).toBeDefined();
97+
expect(config?.defaultProps?.title).toBeDefined();
98+
});
99+
100+
it('should have valid defaultProps for table component', () => {
101+
const config = ComponentRegistry.getConfig('table');
102+
expect(config).toBeDefined();
103+
expect(config?.defaultProps).toBeDefined();
104+
expect(config?.defaultProps?.columns).toBeDefined();
105+
expect(Array.isArray(config?.defaultProps?.columns)).toBe(true);
106+
expect(config?.defaultProps?.data).toBeDefined();
107+
expect(Array.isArray(config?.defaultProps?.data)).toBe(true);
108+
});
109+
110+
it('should have valid defaultProps with initial dimensions for div component', () => {
111+
const config = ComponentRegistry.getConfig('div');
112+
expect(config).toBeDefined();
113+
expect(config?.defaultProps).toBeDefined();
114+
expect(config?.defaultProps?.className).toBeDefined();
115+
// Should have some minimum dimensions to avoid collapsing
116+
expect(config?.defaultProps?.className).toContain('min-h');
117+
});
118+
119+
it('should have defaultChildren defined for components that need them', () => {
120+
const componentsWithChildren = ['span', 'accordion', 'tabs', 'collapsible'];
121+
122+
componentsWithChildren.forEach(type => {
123+
const config = ComponentRegistry.getConfig(type);
124+
expect(config).toBeDefined();
125+
expect(config?.defaultChildren || config?.defaultProps).toBeDefined();
126+
});
127+
});
128+
});

packages/renderer/src/__tests__/registry.test.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,46 @@ describe('@object-ui/renderer - Registry', () => {
9797

9898
consoleWarnSpy.mockRestore();
9999
});
100+
101+
it('should support defaultProps in component metadata', () => {
102+
const TestComponent: ComponentRenderer = ({ schema }) => (
103+
<div>{schema.label}</div>
104+
);
105+
106+
ComponentRegistry.register('test-with-defaults', TestComponent, {
107+
label: 'Test With Defaults',
108+
defaultProps: {
109+
label: 'Default Label',
110+
variant: 'primary'
111+
}
112+
});
113+
114+
const config = ComponentRegistry.getConfig('test-with-defaults');
115+
expect(config).toBeDefined();
116+
expect(config?.defaultProps).toBeDefined();
117+
expect(config?.defaultProps?.label).toBe('Default Label');
118+
expect(config?.defaultProps?.variant).toBe('primary');
119+
});
120+
121+
it('should support defaultChildren in component metadata', () => {
122+
const TestComponent: ComponentRenderer = ({ schema }) => (
123+
<div>{schema.type}</div>
124+
);
125+
126+
ComponentRegistry.register('test-with-children', TestComponent, {
127+
label: 'Test With Children',
128+
defaultChildren: [
129+
{ type: 'text', content: 'Child 1' },
130+
{ type: 'text', content: 'Child 2' }
131+
]
132+
});
133+
134+
const config = ComponentRegistry.getConfig('test-with-children');
135+
expect(config).toBeDefined();
136+
expect(config?.defaultChildren).toBeDefined();
137+
expect(config?.defaultChildren).toHaveLength(2);
138+
expect(config?.defaultChildren?.[0].type).toBe('text');
139+
expect(config?.defaultChildren?.[0].content).toBe('Child 1');
140+
});
100141
});
101142
});

packages/renderer/src/renderers/basic/div.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ ComponentRegistry.register('div',
1111
label: 'Container',
1212
inputs: [
1313
{ name: 'className', type: 'string', label: 'CSS Class' }
14-
]
14+
],
15+
defaultProps: {
16+
className: 'p-4 border border-dashed border-gray-300 rounded min-h-[100px]'
17+
}
1518
}
1619
);

packages/renderer/src/renderers/basic/separator.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ ComponentRegistry.register('separator',
1616
label: 'Orientation'
1717
},
1818
{ name: 'className', type: 'string', label: 'CSS Class' }
19-
]
19+
],
20+
defaultProps: {
21+
orientation: 'horizontal',
22+
className: 'my-4'
23+
}
2024
}
2125
);

packages/renderer/src/renderers/basic/span.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ ComponentRegistry.register('span',
1111
label: 'Inline Container',
1212
inputs: [
1313
{ name: 'className', type: 'string', label: 'CSS Class' }
14+
],
15+
defaultProps: {
16+
className: 'px-2 py-1'
17+
},
18+
defaultChildren: [
19+
{ type: 'text', content: 'Inline text' }
1420
]
1521
}
1622
);

packages/renderer/src/renderers/basic/text.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ ComponentRegistry.register('text',
88
label: 'Text',
99
inputs: [
1010
{ name: 'content', type: 'string', label: 'Content', required: true }
11-
]
11+
],
12+
defaultProps: {
13+
content: 'Text content'
14+
}
1215
}
1316
);

packages/renderer/src/renderers/complex/carousel.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ ComponentRegistry.register('carousel',
4444
},
4545
{ name: 'itemClassName', type: 'string', label: 'Item CSS Class' },
4646
{ name: 'className', type: 'string', label: 'Container CSS Class' }
47-
]
47+
],
48+
defaultProps: {
49+
orientation: 'horizontal',
50+
showArrows: true,
51+
items: [
52+
[{ type: 'div', className: 'p-8 border rounded bg-slate-50', body: [{ type: 'text', content: 'Slide 1' }] }],
53+
[{ type: 'div', className: 'p-8 border rounded bg-slate-50', body: [{ type: 'text', content: 'Slide 2' }] }],
54+
[{ type: 'div', className: 'p-8 border rounded bg-slate-50', body: [{ type: 'text', content: 'Slide 3' }] }]
55+
],
56+
className: 'w-full max-w-xs'
57+
}
4858
}
4959
);

packages/renderer/src/renderers/complex/resizable.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ ComponentRegistry.register('resizable',
3838
description: 'Array of { defaultSize, minSize, maxSize, content }'
3939
},
4040
{ name: 'className', type: 'string', label: 'CSS Class' }
41-
]
41+
],
42+
defaultProps: {
43+
direction: 'horizontal',
44+
minHeight: '200px',
45+
withHandle: true,
46+
panels: [
47+
{ defaultSize: 50, content: [{ type: 'div', className: 'p-4', body: [{ type: 'text', content: 'Panel 1' }] }] },
48+
{ defaultSize: 50, content: [{ type: 'div', className: 'p-4', body: [{ type: 'text', content: 'Panel 2' }] }] }
49+
],
50+
className: 'rounded-lg border'
51+
}
4252
}
4353
);

packages/renderer/src/renderers/complex/scroll-area.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ ComponentRegistry.register('scroll-area',
1717
{ name: 'orientation', type: 'enum', enum: ['vertical', 'horizontal', 'both'], defaultValue: 'vertical', label: 'Orientation' },
1818
{ name: 'content', type: 'slot', label: 'Content' },
1919
{ name: 'className', type: 'string', label: 'CSS Class' }
20-
]
20+
],
21+
defaultProps: {
22+
height: '200px',
23+
width: '100%',
24+
orientation: 'vertical',
25+
content: [
26+
{ type: 'div', className: 'p-4', body: [{ type: 'text', content: 'Scrollable content goes here. Add more content to see scrolling behavior.' }] }
27+
],
28+
className: 'rounded-md border'
29+
}
2130
}
2231
);

packages/renderer/src/renderers/complex/table.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ ComponentRegistry.register('table',
6363
description: 'Array of objects'
6464
},
6565
{ name: 'className', type: 'string', label: 'CSS Class' }
66-
]
66+
],
67+
defaultProps: {
68+
caption: 'Table Caption',
69+
columns: [
70+
{ header: 'Column 1', accessorKey: 'col1' },
71+
{ header: 'Column 2', accessorKey: 'col2' },
72+
{ header: 'Column 3', accessorKey: 'col3' }
73+
],
74+
data: [
75+
{ col1: 'Row 1, Col 1', col2: 'Row 1, Col 2', col3: 'Row 1, Col 3' },
76+
{ col1: 'Row 2, Col 1', col2: 'Row 2, Col 2', col3: 'Row 2, Col 3' },
77+
{ col1: 'Row 3, Col 1', col2: 'Row 3, Col 2', col3: 'Row 3, Col 3' }
78+
]
79+
}
6780
}
6881
);

0 commit comments

Comments
 (0)