Skip to content

Commit 2b79c44

Browse files
Copilothotlong
andcommitted
Add field type evaluation section to ROADMAP_DESIGNER.md
Evaluates @object-ui/fields field types for form designer integration. Adds comprehensive Section 10 covering: - Complete inventory of all 36 field widgets with type/renderer mapping - Gap analysis per designer (DataModel, Page, View) - Proposed DESIGNER_FIELD_TYPES constant - Integration plan per designer component - Type safety recommendations (FieldTypeName, DataModelField) - Priority phasing with effort estimates Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent aad9481 commit 2b79c44

File tree

1 file changed

+372
-1
lines changed

1 file changed

+372
-1
lines changed

ROADMAP_DESIGNER.md

Lines changed: 372 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Designer UX Analysis & Improvement Plan
22

3-
> **Last Updated:** February 12, 2026
3+
> **Last Updated:** February 16, 2026
44
> **Package:** `@object-ui/plugin-designer`
55
> **Source:** `packages/plugin-designer/src/`
66
@@ -500,6 +500,377 @@ This is the **most complete** designer:
500500

501501
---
502502

503+
## 10. Field Type Evaluation for Form Designer
504+
505+
> **Last Updated:** February 16, 2026
506+
> **Related Packages:** `@object-ui/fields`, `@object-ui/types`, `@object-ui/plugin-designer`
507+
508+
### 10.1 Overview
509+
510+
The `@object-ui/fields` package provides **36 field widget implementations** covering
511+
text, numeric, date/time, selection, file, contact, computed, and visual field types.
512+
The `@object-ui/types` package defines **35 typed metadata interfaces** in
513+
`field-types.ts` plus a `FieldMetadata` union type. However, the designer components
514+
in `@object-ui/plugin-designer` expose only a **fraction** of these field types to
515+
users, creating a significant gap between available capabilities and designer UX.
516+
517+
### 10.2 Complete Field Type Inventory
518+
519+
The table below catalogs all field types available in `@object-ui/fields`, their
520+
corresponding type definitions in `@object-ui/types`, and their current status in
521+
each designer.
522+
523+
#### Category: Basic Text
524+
525+
| Field Type | Widget File | Type Interface | Cell Renderer | Form Mapper | DataModel | Page Palette |
526+
|------------|-------------|----------------|---------------|-------------|-----------|--------------|
527+
| `text` | `TextField.tsx` | `TextFieldMetadata` | `TextCellRenderer` | `field:text` | ✅ Default | `input` |
528+
| `textarea` | `TextAreaField.tsx` | `TextareaFieldMetadata` | `TextCellRenderer` | `field:textarea` | ❌ | `textarea` |
529+
| `markdown` | `RichTextField.tsx` | `MarkdownFieldMetadata` | `TextCellRenderer` | `field:markdown` | ❌ | ❌ |
530+
| `html` | `RichTextField.tsx` | `HtmlFieldMetadata` | `TextCellRenderer` | `field:html` | ❌ | ❌ |
531+
| `code` | `CodeField.tsx` | `CodeFieldMetadata` | — | — | ❌ | ❌ |
532+
533+
#### Category: Numeric
534+
535+
| Field Type | Widget File | Type Interface | Cell Renderer | Form Mapper | DataModel | Page Palette |
536+
|------------|-------------|----------------|---------------|-------------|-----------|--------------|
537+
| `number` | `NumberField.tsx` | `NumberFieldMetadata` | `NumberCellRenderer` | `field:number` | ❌ | ❌ |
538+
| `currency` | `CurrencyField.tsx` | `CurrencyFieldMetadata` | `CurrencyCellRenderer` | `field:currency` | ❌ | ❌ |
539+
| `percent` | `PercentField.tsx` | `PercentFieldMetadata` | `PercentCellRenderer` | `field:percent` | ❌ | ❌ |
540+
| `slider` | `SliderField.tsx` | `SliderFieldMetadata` | — | — | ❌ | ❌ |
541+
| `rating` | `RatingField.tsx` | `RatingFieldMetadata` | — | — | ❌ | ❌ |
542+
543+
#### Category: Date & Time
544+
545+
| Field Type | Widget File | Type Interface | Cell Renderer | Form Mapper | DataModel | Page Palette |
546+
|------------|-------------|----------------|---------------|-------------|-----------|--------------|
547+
| `date` | `DateField.tsx` | `DateFieldMetadata` | `DateCellRenderer` | `field:date` | ❌ | ❌ |
548+
| `datetime` | `DateTimeField.tsx` | `DateTimeFieldMetadata` | `DateTimeCellRenderer` | `field:datetime` | ✅ (default entity) | ❌ |
549+
| `time` | `TimeField.tsx` | `TimeFieldMetadata` | `TextCellRenderer` | `field:time` | ❌ | ❌ |
550+
551+
#### Category: Selection & Lookup
552+
553+
| Field Type | Widget File | Type Interface | Cell Renderer | Form Mapper | DataModel | Page Palette |
554+
|------------|-------------|----------------|---------------|-------------|-----------|--------------|
555+
| `boolean` | `BooleanField.tsx` | `BooleanFieldMetadata` | `BooleanCellRenderer` | `field:boolean` | ❌ | `checkbox` |
556+
| `select` | `SelectField.tsx` | `SelectFieldMetadata` | `SelectCellRenderer` | `field:select` | ❌ | `select` |
557+
| `lookup` | `LookupField.tsx` | `LookupFieldMetadata` | `LookupCellRenderer` | `field:lookup` | ❌ | ❌ |
558+
| `master_detail` | `MasterDetailField.tsx` | `MasterDetailFieldMetadata` | `LookupCellRenderer` | `field:master_detail` | ❌ | ❌ |
559+
560+
#### Category: Contact & Identity
561+
562+
| Field Type | Widget File | Type Interface | Cell Renderer | Form Mapper | DataModel | Page Palette |
563+
|------------|-------------|----------------|---------------|-------------|-----------|--------------|
564+
| `email` | `EmailField.tsx` | `EmailFieldMetadata` | `EmailCellRenderer` | `field:email` | ❌ | ❌ |
565+
| `phone` | `PhoneField.tsx` | `PhoneFieldMetadata` | `PhoneCellRenderer` | `field:phone` | ❌ | ❌ |
566+
| `url` | `UrlField.tsx` | `UrlFieldMetadata` | `UrlCellRenderer` | `field:url` | ❌ | ❌ |
567+
| `password` | `PasswordField.tsx` | `PasswordFieldMetadata` | *(masked)* | `field:password` | ❌ | ❌ |
568+
| `user` | `UserField.tsx` | `UserFieldMetadata` | `UserCellRenderer` | — | ❌ | ❌ |
569+
| `avatar` | `AvatarField.tsx` | `AvatarFieldMetadata` | — | — | ❌ | ❌ |
570+
571+
#### Category: File & Media
572+
573+
| Field Type | Widget File | Type Interface | Cell Renderer | Form Mapper | DataModel | Page Palette |
574+
|------------|-------------|----------------|---------------|-------------|-----------|--------------|
575+
| `file` | `FileField.tsx` | `FileFieldMetadata` | `FileCellRenderer` | `field:file` | ❌ | ❌ |
576+
| `image` | `ImageField.tsx` | `ImageFieldMetadata` | `ImageCellRenderer` | `field:image` | ❌ | ❌ |
577+
| `signature` | `SignatureField.tsx` | `SignatureFieldMetadata` | — | — | ❌ | ❌ |
578+
| `qrcode` | `QRCodeField.tsx` | `QRCodeFieldMetadata` | — | — | ❌ | ❌ |
579+
580+
#### Category: Location & Address
581+
582+
| Field Type | Widget File | Type Interface | Cell Renderer | Form Mapper | DataModel | Page Palette |
583+
|------------|-------------|----------------|---------------|-------------|-----------|--------------|
584+
| `location` | `LocationField.tsx` | `LocationFieldMetadata` | `TextCellRenderer` | `field:location` | ❌ | ❌ |
585+
| `address` | `AddressField.tsx` | `AddressFieldMetadata` | — | — | ❌ | ❌ |
586+
| `geolocation` | `GeolocationField.tsx` | `GeolocationFieldMetadata` | — | — | ❌ | ❌ |
587+
588+
#### Category: Computed & Auto-generated
589+
590+
| Field Type | Widget File | Type Interface | Cell Renderer | Form Mapper | DataModel | Page Palette |
591+
|------------|-------------|----------------|---------------|-------------|-----------|--------------|
592+
| `formula` | `FormulaField.tsx` | `FormulaFieldMetadata` | `FormulaCellRenderer` | `field:formula` | ❌ | ❌ |
593+
| `summary` | `SummaryField.tsx` | `SummaryFieldMetadata` | `FormulaCellRenderer` | `field:summary` | ❌ | ❌ |
594+
| `auto_number` | `AutoNumberField.tsx` | `AutoNumberFieldMetadata` | `TextCellRenderer` | `field:auto_number` | ❌ | ❌ |
595+
596+
#### Category: Complex & Visual
597+
598+
| Field Type | Widget File | Type Interface | Cell Renderer | Form Mapper | DataModel | Page Palette |
599+
|------------|-------------|----------------|---------------|-------------|-----------|--------------|
600+
| `object` | `ObjectField.tsx` | `ObjectFieldMetadata` | *[Object]* | — | ❌ | ❌ |
601+
| `vector` | `VectorField.tsx` | `VectorFieldMetadata` | *[Vector]* | — | ❌ | ❌ |
602+
| `grid` | `GridField.tsx` | `GridFieldMetadata` | *[Grid]* | — | ❌ | ❌ |
603+
| `color` | `ColorField.tsx` | `ColorFieldMetadata` | — | — | ❌ | ❌ |
604+
605+
### 10.3 Gap Analysis by Designer
606+
607+
#### DataModelDesigner
608+
609+
**Current state:** When a field is added via `handleAddField` (`DataModelDesigner.tsx:258`),
610+
the type is hardcoded to `'text'`. The field type is displayed as a plain text label
611+
(`DataModelDesigner.tsx:712`) but there is **no UI to change the field type** after
612+
creation. The inline editing mode (`DataModelDesigner.tsx:273–306`) only supports
613+
editing the field name.
614+
615+
**`DataModelField.type`** in `@object-ui/types` (`designer.ts:156`) is typed as a
616+
generic `string`, not a union of valid `@object-ui/fields` types. This means:
617+
- No TypeScript-level validation of field type values
618+
- No autocomplete assistance for developers
619+
- No compile-time guarantee that a field type maps to an existing widget
620+
621+
**Key gaps:**
622+
1. No field type selector dropdown when adding/editing fields
623+
2. No reuse of `FieldMetadata` union type from `@object-ui/types/field-types.ts`
624+
3. No visual distinction between field types (icons, colors, badges)
625+
4. Default entity template only includes `uuid` and `datetime` — no standard business fields
626+
627+
#### PageDesigner
628+
629+
**Current state:** The `DEFAULT_PALETTE` (`PageDesigner.tsx:740–773`) contains 14
630+
generic component types across 3 categories (Layout, Form, Data). The Form category
631+
has only 5 items: `input`, `textarea`, `select`, `checkbox`, `button`.
632+
633+
**Key gaps:**
634+
1. Form palette uses generic HTML-like type names (`input`, `checkbox`) rather than
635+
`@object-ui/fields` type names (`text`, `boolean`, `email`, `phone`)
636+
2. Missing a dedicated **Fields** palette category showcasing all 36 field widgets
637+
3. No mapping between palette items and `@object-ui/fields` `FieldWidgetProps` interface
638+
4. No preview rendering using actual field widgets from `@object-ui/fields`
639+
640+
#### ViewDesigner
641+
642+
**Current state:** The ViewDesigner shows field types as plain text badges
643+
(`ViewDesigner.tsx:533`). It relies on the `availableFields` prop to receive
644+
`Array<{ name: string; label: string; type: string }>` from the parent. Type display
645+
is the most complete among designers, but still lacks visual indicators.
646+
647+
**Key gaps:**
648+
1. Field type badges are plain text with no icons or colors per type
649+
2. No field type grouping/categorization in the Available Fields panel
650+
3. No type-specific column configuration (e.g., currency format, date format)
651+
652+
### 10.4 Recommended `DESIGNER_FIELD_TYPES` Constant
653+
654+
A centralized constant should be created to define all available field types for
655+
designer selection, leveraging the `FieldMetadata` union type from `@object-ui/types`.
656+
657+
**Proposed location:** `packages/plugin-designer/src/constants/fieldTypes.ts`
658+
659+
```typescript
660+
import type { LucideIcon } from 'lucide-react';
661+
import {
662+
Type, Hash, Calendar, Clock, ToggleLeft, List,
663+
Link, Mail, Phone, Globe, Lock, File, Image,
664+
MapPin, Home, Navigation, Calculator, Sigma, Binary,
665+
User, Palette, Code2, Star, PenTool, QrCode,
666+
Grid3X3, Braces, Database as DatabaseIcon, SlidersHorizontal,
667+
} from 'lucide-react';
668+
669+
export interface DesignerFieldTypeOption {
670+
/** Field type identifier — matches @object-ui/fields registry key */
671+
type: string;
672+
/** Display label */
673+
label: string;
674+
/** Lucide icon component */
675+
icon: LucideIcon;
676+
/** Category for grouping in palette/dropdown */
677+
category: 'text' | 'number' | 'datetime' | 'selection' | 'contact'
678+
| 'file' | 'location' | 'computed' | 'complex' | 'visual';
679+
/** Short description for tooltips */
680+
description: string;
681+
}
682+
683+
export const DESIGNER_FIELD_TYPES: DesignerFieldTypeOption[] = [
684+
// Text
685+
{ type: 'text', label: 'Text', icon: Type, category: 'text',
686+
description: 'Single-line text input' },
687+
{ type: 'textarea', label: 'Long Text', icon: Type, category: 'text',
688+
description: 'Multi-line text area' },
689+
{ type: 'markdown', label: 'Markdown', icon: Code2, category: 'text',
690+
description: 'Markdown-formatted rich text' },
691+
{ type: 'html', label: 'Rich Text', icon: Code2, category: 'text',
692+
description: 'HTML rich text editor' },
693+
{ type: 'code', label: 'Code', icon: Code2, category: 'text',
694+
description: 'Code editor with syntax highlighting' },
695+
696+
// Number
697+
{ type: 'number', label: 'Number', icon: Hash, category: 'number',
698+
description: 'Numeric input with precision control' },
699+
{ type: 'currency', label: 'Currency', icon: Hash, category: 'number',
700+
description: 'Monetary value with currency symbol' },
701+
{ type: 'percent', label: 'Percent', icon: Hash, category: 'number',
702+
description: 'Percentage value with progress bar' },
703+
{ type: 'slider', label: 'Slider', icon: SlidersHorizontal, category: 'number',
704+
description: 'Numeric range slider' },
705+
{ type: 'rating', label: 'Rating', icon: Star, category: 'number',
706+
description: 'Star rating input' },
707+
708+
// Date & Time
709+
{ type: 'date', label: 'Date', icon: Calendar, category: 'datetime',
710+
description: 'Date picker' },
711+
{ type: 'datetime', label: 'Date & Time', icon: Calendar, category: 'datetime',
712+
description: 'Date and time picker' },
713+
{ type: 'time', label: 'Time', icon: Clock, category: 'datetime',
714+
description: 'Time picker' },
715+
716+
// Selection
717+
{ type: 'boolean', label: 'Boolean', icon: ToggleLeft, category: 'selection',
718+
description: 'True/false toggle' },
719+
{ type: 'select', label: 'Select', icon: List, category: 'selection',
720+
description: 'Dropdown with predefined options' },
721+
{ type: 'lookup', label: 'Lookup', icon: Link, category: 'selection',
722+
description: 'Reference to another object' },
723+
{ type: 'master_detail', label: 'Master-Detail', icon: Link, category: 'selection',
724+
description: 'Parent-child relationship with cascade delete' },
725+
726+
// Contact
727+
{ type: 'email', label: 'Email', icon: Mail, category: 'contact',
728+
description: 'Email address with validation' },
729+
{ type: 'phone', label: 'Phone', icon: Phone, category: 'contact',
730+
description: 'Phone number input' },
731+
{ type: 'url', label: 'URL', icon: Globe, category: 'contact',
732+
description: 'Web address with validation' },
733+
{ type: 'password', label: 'Password', icon: Lock, category: 'contact',
734+
description: 'Masked password input' },
735+
{ type: 'user', label: 'User', icon: User, category: 'contact',
736+
description: 'User reference with avatar' },
737+
{ type: 'avatar', label: 'Avatar', icon: User, category: 'contact',
738+
description: 'User avatar image' },
739+
740+
// File & Media
741+
{ type: 'file', label: 'File', icon: File, category: 'file',
742+
description: 'File upload with type/size validation' },
743+
{ type: 'image', label: 'Image', icon: Image, category: 'file',
744+
description: 'Image upload with preview' },
745+
{ type: 'signature', label: 'Signature', icon: PenTool, category: 'file',
746+
description: 'Digital signature capture' },
747+
{ type: 'qrcode', label: 'QR Code', icon: QrCode, category: 'file',
748+
description: 'QR code generator/scanner' },
749+
750+
// Location
751+
{ type: 'location', label: 'Location', icon: MapPin, category: 'location',
752+
description: 'Map-based location picker' },
753+
{ type: 'address', label: 'Address', icon: Home, category: 'location',
754+
description: 'Structured address fields' },
755+
{ type: 'geolocation', label: 'Geolocation', icon: Navigation, category: 'location',
756+
description: 'GPS coordinates input' },
757+
758+
// Computed
759+
{ type: 'formula', label: 'Formula', icon: Calculator, category: 'computed',
760+
description: 'Calculated field from expression' },
761+
{ type: 'summary', label: 'Summary', icon: Sigma, category: 'computed',
762+
description: 'Roll-up aggregation from related records' },
763+
{ type: 'auto_number', label: 'Auto Number', icon: Binary, category: 'computed',
764+
description: 'Auto-incrementing number' },
765+
766+
// Complex
767+
{ type: 'object', label: 'Object', icon: Braces, category: 'complex',
768+
description: 'Nested JSON object' },
769+
{ type: 'vector', label: 'Vector', icon: DatabaseIcon, category: 'complex',
770+
description: 'Embedding vector for AI/ML' },
771+
{ type: 'grid', label: 'Grid', icon: Grid3X3, category: 'complex',
772+
description: 'Inline sub-table/spreadsheet' },
773+
{ type: 'color', label: 'Color', icon: Palette, category: 'visual',
774+
description: 'Color picker' },
775+
];
776+
```
777+
778+
### 10.5 Integration Plan per Designer
779+
780+
#### DataModelDesigner — Field Type Selector
781+
782+
Add a `<select>` dropdown next to each field's type display, populated from
783+
`DESIGNER_FIELD_TYPES`. When a field type is changed, update the entity's field
784+
array via `pushState()`.
785+
786+
**Implementation points:**
787+
- Replace the read-only `{field.type}` span (`DataModelDesigner.tsx:712`) with a
788+
`<select>` element grouped by `category`
789+
- Add an `onChangeFieldType(entityId, fieldIndex, newType)` handler
790+
- Show field type icons in the property editor panel when an entity is selected
791+
- Update the type of `DataModelField.type` in `@object-ui/types/designer.ts` to
792+
reference the `FieldMetadata` union's type discriminant for type safety
793+
794+
#### PageDesigner — Fields Palette Category
795+
796+
Add a fourth palette category **"Fields"** to `DEFAULT_PALETTE`, populated from
797+
`DESIGNER_FIELD_TYPES`. Each palette item should map to the corresponding
798+
`@object-ui/fields` widget via `ComponentRegistry.resolve('field:<type>')`.
799+
800+
**Proposed palette addition:**
801+
```typescript
802+
{
803+
name: 'fields',
804+
label: 'Fields',
805+
items: DESIGNER_FIELD_TYPES.map(ft => ({
806+
type: `field:${ft.type}`,
807+
label: ft.label,
808+
icon: ft.icon.name,
809+
defaultSize: { width: 300, height: 60 },
810+
defaultProps: { fieldType: ft.type },
811+
})),
812+
}
813+
```
814+
815+
**Implementation points:**
816+
- Import `DESIGNER_FIELD_TYPES` from `./constants/fieldTypes`
817+
- Render field type icons in palette items
818+
- When a field palette item is dropped on canvas, the component renders the
819+
actual field widget from `@object-ui/fields` via `ComponentRegistry`
820+
- The property editor should expose field-type-specific props (e.g., `currency`
821+
for currency fields, `options` for select fields)
822+
823+
#### ViewDesigner — Field Type Badges with Icons
824+
825+
Enhance the Available Fields panel (`ViewDesigner.tsx:520–537`) to show field
826+
type icons from `DESIGNER_FIELD_TYPES` alongside field names, and group fields
827+
by category.
828+
829+
**Implementation points:**
830+
- Import field type icons from `DESIGNER_FIELD_TYPES`
831+
- Replace plain text type badge with icon + colored badge
832+
- Optionally group available fields by field type category
833+
834+
### 10.6 Type Safety Recommendations
835+
836+
1. **Add `FieldTypeName` type to `@object-ui/types`:**
837+
```typescript
838+
export type FieldTypeName = FieldMetadata['type'];
839+
// Results in: 'text' | 'textarea' | 'markdown' | 'html' | 'number' | ...
840+
```
841+
842+
2. **Update `DataModelField.type` in `designer.ts`:**
843+
```typescript
844+
import type { FieldTypeName } from './field-types';
845+
846+
export interface DataModelField {
847+
name: string;
848+
label?: string;
849+
type: FieldTypeName; // Changed from generic `string`
850+
// ...
851+
}
852+
```
853+
854+
3. **Update `mapFieldTypeToFormType` in `@object-ui/fields`** to cover all 36
855+
field types (currently missing: `color`, `slider`, `rating`, `code`, `avatar`,
856+
`address`, `geolocation`, `signature`, `qrcode`).
857+
858+
### 10.7 Priority & Phasing
859+
860+
| Priority | Task | Effort |
861+
|----------|------|--------|
862+
| 🔴 P0 | Create `DESIGNER_FIELD_TYPES` constant | 0.5 day |
863+
| 🔴 P0 | Add field type selector dropdown to DataModelDesigner | 1 day |
864+
| 🟠 P1 | Add Fields palette category to PageDesigner | 1 day |
865+
| 🟠 P1 | Add `FieldTypeName` type and update `DataModelField` | 0.5 day |
866+
| 🟡 P2 | Enhance ViewDesigner field type badges with icons | 0.5 day |
867+
| 🟡 P2 | Complete `mapFieldTypeToFormType` for all 36 types | 0.5 day |
868+
| 🟢 P3 | Type-specific property editors per field type | 3–5 days |
869+
870+
**Total estimated effort:** 7–9.5 developer days
871+
872+
---
873+
503874
## Appendix A: File Reference Index
504875

505876
| File | Lines | Component | Registration ID |

0 commit comments

Comments
 (0)