Skip to content

Commit 44c3079

Browse files
committed
feat: add ModalForm and SplitForm components with corresponding schemas and rendering logic
- Introduced ModalForm component for rendering forms in a modal dialog. - Introduced SplitForm component for rendering forms in a resizable split-panel layout. - Implemented loading, error handling, and data fetching for both components. - Added tests for ModalForm and SplitForm to ensure correct rendering and functionality. - Configured Vitest for testing with setup files and environment settings.
1 parent e2088b4 commit 44c3079

File tree

12 files changed

+1799
-15
lines changed

12 files changed

+1799
-15
lines changed

ROADMAP.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
| @object-ui/fields | ✅ Complete | 95% | 36 widgets, 20+ cell renderers |
1919
| @object-ui/layout | 🟡 Partial | 60% | Basic layouts, missing responsive grid |
2020
| @object-ui/react | ✅ Complete | 100% | SchemaRenderer, hooks, providers |
21-
| @object-ui/plugin-form | 🟡 Partial | 30% | Only `simple` form, missing 5 variants |
21+
| @object-ui/plugin-form | ✅ Complete | 90% | All 6 variants (simple/tabbed/wizard/split/drawer/modal), FormField enhancements |
2222
| @object-ui/plugin-grid | ✅ Complete | 95% | Full ListView support |
2323
| @object-ui/plugin-aggrid | ✅ Complete | 100% | AG Grid integration |
2424
| @object-ui/plugin-kanban | ✅ Complete | 100% | Kanban board |
@@ -57,15 +57,15 @@ FormView.type: 'simple' | 'tabbed' | 'wizard' | 'split' | 'drawer' | 'modal'
5757
**Current State:** Only `simple` form implemented.
5858

5959
**Missing Features:**
60-
- [ ] Tabbed Form - Fields organized in tab groups
61-
- [ ] Wizard Form - Multi-step form with navigation
62-
- [ ] Split Form - Side-by-side panels
63-
- [ ] Drawer Form - Slide-out form panel
64-
- [ ] Modal Form - Dialog-based form
65-
- [ ] Section/Group support (collapsible, columns per section)
66-
- [ ] FormField.colSpan support
67-
- [ ] FormField.dependsOn (field dependencies)
68-
- [ ] FormField.widget (custom widget override)
60+
- [x] Tabbed Form - Fields organized in tab groups
61+
- [x] Wizard Form - Multi-step form with navigation
62+
- [x] Split Form - Side-by-side panels (ResizablePanelGroup)
63+
- [x] Drawer Form - Slide-out form panel (Sheet)
64+
- [x] Modal Form - Dialog-based form (Dialog)
65+
- [x] Section/Group support (collapsible, columns per section)
66+
- [x] FormField.colSpan support
67+
- [ ] FormField.dependsOn (field dependencies) — type defined, runtime evaluation pending
68+
- [x] FormField.widget (custom widget override)
6969

7070
---
7171

packages/components/src/renderers/form/form.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,17 @@ ComponentRegistry.register('form',
228228
disabled: fieldDisabled = false,
229229
validation = {},
230230
condition,
231+
colSpan,
232+
hidden,
233+
widget,
234+
visibleOn,
235+
readonly,
231236
...fieldProps
232237
} = field;
233238

239+
// Skip hidden fields
240+
if (hidden) return null;
241+
234242
// Handle conditional rendering with null/undefined safety
235243
if (condition) {
236244
const watchField = condition.field;
@@ -264,14 +272,25 @@ ComponentRegistry.register('form',
264272
// Use field.id or field.name for stable keys (never use index alone)
265273
const fieldKey = field.id ?? name;
266274

275+
// Resolve the component type: prefer widget override, fallback to field type
276+
const resolvedType = widget || type;
277+
278+
// colSpan classes for grid layout
279+
const colSpanClass = colSpan && colSpan > 1
280+
? colSpan === 2 ? 'col-span-2'
281+
: colSpan === 3 ? 'col-span-3'
282+
: colSpan >= 4 ? 'col-span-4'
283+
: ''
284+
: '';
285+
267286
return (
268287
<FormField
269288
key={fieldKey}
270289
control={form.control}
271290
name={name}
272291
rules={rules}
273292
render={({ field: formField }) => (
274-
<FormItem>
293+
<FormItem className={colSpanClass || undefined}>
275294
{label && (
276295
<FormLabel>
277296
{label}
@@ -283,8 +302,8 @@ ComponentRegistry.register('form',
283302
</FormLabel>
284303
)}
285304
<FormControl>
286-
{/* Render the actual field component based on type */}
287-
{renderFieldComponent(type, {
305+
{/* Render the actual field component based on resolved type */}
306+
{renderFieldComponent(resolvedType, {
288307
...fieldProps,
289308
// specialized fields needs raw metadata, but we should traverse down if it exists
290309
// field is the field configuration loop variable
@@ -293,7 +312,7 @@ ComponentRegistry.register('form',
293312
inputType: fieldProps.inputType,
294313
options: fieldProps.options,
295314
placeholder: fieldProps.placeholder,
296-
disabled: disabled || fieldDisabled || isSubmitting,
315+
disabled: disabled || fieldDisabled || readonly || isSubmitting,
297316
})}
298317
</FormControl>
299318
{description && (

0 commit comments

Comments
 (0)