@@ -128,18 +128,54 @@ export const ObjectForm: React.FC<ObjectFormProps> = ({
128128 } ;
129129
130130 // Add field-specific properties
131- if ( field . type === 'select' || field . type === 'lookup' ) {
131+ if ( field . type === 'select' || field . type === 'lookup' || field . type === 'master_detail' ) {
132132 formField . options = field . options || [ ] ;
133+ formField . multiple = field . multiple ;
133134 }
134135
135- if ( field . type === 'number' || field . type === 'currency' ) {
136+ if ( field . type === 'number' || field . type === 'currency' || field . type === 'percent' ) {
136137 formField . min = field . min ;
137138 formField . max = field . max ;
138139 formField . step = field . precision ? Math . pow ( 10 , - field . precision ) : undefined ;
139140 }
140141
141- if ( field . type === 'text' || field . type === 'textarea' ) {
142- formField . maxLength = field . maxLength ;
142+ if ( field . type === 'text' || field . type === 'textarea' || field . type === 'markdown' || field . type === 'html' ) {
143+ formField . maxLength = field . max_length ;
144+ formField . minLength = field . min_length ;
145+ }
146+
147+ if ( field . type === 'file' || field . type === 'image' ) {
148+ formField . multiple = field . multiple ;
149+ formField . accept = field . accept ?. join ( ',' ) ;
150+ // Add validation hints for file size and dimensions
151+ if ( field . max_size ) {
152+ formField . description = ( formField . description || '' ) + ` (Max size: ${ formatFileSize ( field . max_size ) } )` ;
153+ }
154+ }
155+
156+ if ( field . type === 'email' ) {
157+ formField . inputType = 'email' ;
158+ }
159+
160+ if ( field . type === 'phone' ) {
161+ formField . inputType = 'tel' ;
162+ }
163+
164+ if ( field . type === 'url' ) {
165+ formField . inputType = 'url' ;
166+ }
167+
168+ if ( field . type === 'password' ) {
169+ formField . inputType = 'password' ;
170+ }
171+
172+ if ( field . type === 'time' ) {
173+ formField . inputType = 'time' ;
174+ }
175+
176+ // Read-only fields for computed types
177+ if ( field . type === 'formula' || field . type === 'summary' || field . type === 'auto_number' ) {
178+ formField . disabled = true ;
143179 }
144180
145181 generatedFields . push ( formField ) ;
@@ -245,29 +281,84 @@ export const ObjectForm: React.FC<ObjectFormProps> = ({
245281 * `select`). If a field type is not explicitly mapped, the function falls
246282 * back to the generic `"input"` type.
247283 *
284+ * Updated to support all field types from @objectql/types v3.0.1:
285+ * text, textarea, markdown, html, select, date, datetime, time, number,
286+ * currency, percent, boolean, email, phone, url, image, file, location,
287+ * lookup, master_detail, password, formula, summary, auto_number, object,
288+ * vector, grid
289+ *
248290 * @param fieldType - The ObjectQL field type identifier to convert
249291 * (for example: `"text"`, `"number"`, `"date"`, `"lookup"`).
250292 * @returns The normalized form field type string used in the form schema
251293 * (for example: `"input"`, `"textarea"`, `"date-picker"`, `"select"`).
252294 */
253295function mapFieldTypeToFormType ( fieldType : string ) : string {
254296 const typeMap : Record < string , string > = {
297+ // Text-based fields
255298 text : 'input' ,
256299 textarea : 'textarea' ,
300+ markdown : 'textarea' , // Markdown editor (fallback to textarea)
301+ html : 'textarea' , // Rich text editor (fallback to textarea)
302+
303+ // Numeric fields
257304 number : 'input' ,
258305 currency : 'input' ,
259306 percent : 'input' ,
307+
308+ // Date/Time fields
260309 date : 'date-picker' ,
261310 datetime : 'date-picker' ,
311+ time : 'input' , // Time picker (fallback to input with type="time")
312+
313+ // Boolean
262314 boolean : 'switch' ,
315+
316+ // Selection fields
263317 select : 'select' ,
318+ lookup : 'select' ,
319+ master_detail : 'select' ,
320+
321+ // Contact fields
264322 email : 'input' ,
323+ phone : 'input' ,
265324 url : 'input' ,
325+
326+ // File fields
327+ file : 'file-upload' ,
328+ image : 'file-upload' ,
329+
330+ // Special fields
266331 password : 'input' ,
267- lookup : 'select' ,
268- master_detail : 'select' ,
269- fileupload : 'file-upload' ,
332+ location : 'input' , // Location/map field (fallback to input)
333+
334+ // Auto-generated/computed fields (typically read-only)
335+ formula : 'input' ,
336+ summary : 'input' ,
337+ auto_number : 'input' ,
338+
339+ // Complex data types
340+ object : 'input' , // JSON object (fallback to input)
341+ vector : 'input' , // Vector/embedding data (fallback to input)
342+ grid : 'input' , // Grid/table data (fallback to input)
270343 } ;
271344
272345 return typeMap [ fieldType ] || 'input' ;
273346}
347+
348+ /**
349+ * Formats file size in bytes to human-readable string
350+ * @param bytes - File size in bytes
351+ * @returns Formatted string (e.g., "5 MB", "1.5 GB")
352+ */
353+ function formatFileSize ( bytes : number ) : string {
354+ const units = [ 'B' , 'KB' , 'MB' , 'GB' , 'TB' ] ;
355+ let size = bytes ;
356+ let unitIndex = 0 ;
357+
358+ while ( size >= 1024 && unitIndex < units . length - 1 ) {
359+ size /= 1024 ;
360+ unitIndex ++ ;
361+ }
362+
363+ return `${ size . toFixed ( unitIndex > 0 ? 1 : 0 ) } ${ units [ unitIndex ] } ` ;
364+ }
0 commit comments