@k3-universe/react-kit 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/kit/builder/form/components/FormBuilder.d.ts +21 -1
  2. package/dist/kit/builder/form/components/FormBuilder.d.ts.map +1 -1
  3. package/dist/kit/builder/form/components/FormBuilderField.d.ts +5 -5
  4. package/dist/kit/builder/form/components/FormBuilderField.d.ts.map +1 -1
  5. package/dist/kit/builder/form/components/fields/ArrayField.d.ts +3 -0
  6. package/dist/kit/builder/form/components/fields/ArrayField.d.ts.map +1 -0
  7. package/dist/kit/builder/form/components/fields/AutocompleteField.d.ts +3 -0
  8. package/dist/kit/builder/form/components/fields/AutocompleteField.d.ts.map +1 -0
  9. package/dist/kit/builder/form/components/fields/CheckboxField.d.ts +3 -0
  10. package/dist/kit/builder/form/components/fields/CheckboxField.d.ts.map +1 -0
  11. package/dist/kit/builder/form/components/fields/DateField.d.ts +3 -0
  12. package/dist/kit/builder/form/components/fields/DateField.d.ts.map +1 -0
  13. package/dist/kit/builder/form/components/fields/FileField.d.ts +3 -0
  14. package/dist/kit/builder/form/components/fields/FileField.d.ts.map +1 -0
  15. package/dist/kit/builder/form/components/fields/NumberField.d.ts +3 -0
  16. package/dist/kit/builder/form/components/fields/NumberField.d.ts.map +1 -0
  17. package/dist/kit/builder/form/components/fields/ObjectField.d.ts +3 -0
  18. package/dist/kit/builder/form/components/fields/ObjectField.d.ts.map +1 -0
  19. package/dist/kit/builder/form/components/fields/RadioField.d.ts +3 -0
  20. package/dist/kit/builder/form/components/fields/RadioField.d.ts.map +1 -0
  21. package/dist/kit/builder/form/components/fields/SelectField.d.ts +3 -0
  22. package/dist/kit/builder/form/components/fields/SelectField.d.ts.map +1 -0
  23. package/dist/kit/builder/form/components/fields/SwitchField.d.ts +3 -0
  24. package/dist/kit/builder/form/components/fields/SwitchField.d.ts.map +1 -0
  25. package/dist/kit/builder/form/components/fields/TextField.d.ts +3 -0
  26. package/dist/kit/builder/form/components/fields/TextField.d.ts.map +1 -0
  27. package/dist/kit/builder/form/components/fields/TextareaField.d.ts +3 -0
  28. package/dist/kit/builder/form/components/fields/TextareaField.d.ts.map +1 -0
  29. package/dist/kit/builder/form/components/fields/index.d.ts +14 -0
  30. package/dist/kit/builder/form/components/fields/index.d.ts.map +1 -0
  31. package/dist/kit/builder/form/components/fields/types.d.ts +14 -0
  32. package/dist/kit/builder/form/components/fields/types.d.ts.map +1 -0
  33. package/dist/kit/builder/form/utils/field-factories.d.ts +1 -0
  34. package/dist/kit/builder/form/utils/field-factories.d.ts.map +1 -1
  35. package/dist/kit/themes/clean-slate.css +1 -1
  36. package/dist/kit/themes/default.css +1 -1
  37. package/dist/kit/themes/minimal-modern.css +1 -1
  38. package/dist/kit/themes/spotify.css +1 -1
  39. package/package.json +1 -1
  40. package/src/kit/builder/form/components/FormBuilder.tsx +24 -1
  41. package/src/kit/builder/form/components/FormBuilderField.tsx +143 -340
  42. package/src/kit/builder/form/components/fields/ArrayField.tsx +222 -0
  43. package/src/kit/builder/form/components/fields/AutocompleteField.tsx +25 -0
  44. package/src/kit/builder/form/components/fields/CheckboxField.tsx +56 -0
  45. package/src/kit/builder/form/components/fields/DateField.tsx +15 -0
  46. package/src/kit/builder/form/components/fields/FileField.tsx +14 -0
  47. package/src/kit/builder/form/components/fields/NumberField.tsx +15 -0
  48. package/src/kit/builder/form/components/fields/ObjectField.tsx +30 -0
  49. package/src/kit/builder/form/components/fields/RadioField.tsx +29 -0
  50. package/src/kit/builder/form/components/fields/SelectField.tsx +31 -0
  51. package/src/kit/builder/form/components/fields/SwitchField.tsx +56 -0
  52. package/src/kit/builder/form/components/fields/TextField.tsx +18 -0
  53. package/src/kit/builder/form/components/fields/TextareaField.tsx +15 -0
  54. package/src/kit/builder/form/components/fields/index.ts +13 -0
  55. package/src/kit/builder/form/components/fields/types.ts +14 -0
  56. package/src/kit/builder/form/utils/field-factories.ts +13 -0
  57. package/src/stories/kit/builder/Form.ArrayLayouts.stories.tsx +153 -0
  58. package/src/stories/kit/builder/Form.Basic.stories.tsx +2 -0
  59. package/src/stories/kit/builder/Form.Simple.stories.tsx +4 -0
@@ -1,30 +1,33 @@
1
1
  import { useCallback } from 'react';
2
- import { Control, useController, useFieldArray } from 'react-hook-form';
2
+ import { Control, FieldValues, useController } from 'react-hook-form';
3
3
  import { cn } from '../../../../shadcn/lib/utils';
4
- import { Button } from '../../../../shadcn/ui/button';
5
- import { Input } from '../../../../shadcn/ui/input';
6
- import { Textarea } from '../../../../shadcn/ui/textarea';
7
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../../shadcn/ui/select';
8
- import { Checkbox } from '../../../../shadcn/ui/checkbox';
9
- import { RadioGroup, RadioGroupItem } from '../../../../shadcn/ui/radio-group';
10
4
  import { Label } from '../../../../shadcn/ui/label';
11
- import { Card, CardContent, CardHeader, CardTitle } from '../../../../shadcn/ui/card';
12
- import { Plus, Trash2, GripVertical } from 'lucide-react';
13
5
  import { FormBuilderFieldConfig } from './FormBuilder';
14
- import { Autocomplete } from '../../../components/autocomplete/Autocomplete';
15
- import type { AutocompleteOption } from '../../../components/autocomplete/types';
6
+ import {
7
+ AutocompleteField,
8
+ TextField,
9
+ NumberField,
10
+ TextareaField,
11
+ SelectField,
12
+ CheckboxField,
13
+ SwitchField,
14
+ RadioField,
15
+ DateField,
16
+ FileField,
17
+ ObjectField,
18
+ ArrayField,
19
+ } from './fields';
16
20
 
17
21
  export interface FormBuilderFieldProps {
18
22
  field: FormBuilderFieldConfig;
19
- control: Control<any>;
20
- onChange?: (value: any) => void;
21
- onFieldChange?: (name: string, value: any, allValues: Record<string, any>) => void;
23
+ control: Control<FieldValues>;
24
+ onChange?: (value: unknown) => void;
25
+ onFieldChange?: (name: string, value: unknown, allValues: Record<string, unknown>) => void;
22
26
  parentPath?: string;
23
27
  }
24
28
 
25
- export function FormBuilderField({ field, control, onChange, onFieldChange, parentPath }: FormBuilderFieldProps) {
29
+ export function FormBuilderField({ field, control, onChange, parentPath }: FormBuilderFieldProps) {
26
30
  const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name;
27
- const NULL_SENTINEL = '__NULL__';
28
31
 
29
32
  const {
30
33
  field: controllerField,
@@ -35,370 +38,170 @@ export function FormBuilderField({ field, control, onChange, onFieldChange, pare
35
38
  disabled: field.disabled,
36
39
  });
37
40
 
38
- const handleChange = useCallback((value: any) => {
41
+ const handleChange = useCallback((value: unknown) => {
39
42
  controllerField.onChange(value);
40
43
  onChange?.(value);
41
44
  }, [controllerField.onChange, onChange]);
45
+ const baseClassName = cn(
46
+ error && 'border-destructive focus-visible:ring-destructive',
47
+ field.className,
48
+ );
42
49
 
43
- const renderBasicField = () => {
44
- const baseProps = {
45
- id: fieldPath,
46
- disabled: field.disabled,
47
- placeholder: field.placeholder,
48
- className: cn(
49
- error && 'border-destructive focus-visible:ring-destructive',
50
- field.className,
51
- ),
52
- };
53
-
50
+ const renderField = () => {
54
51
  switch (field.type) {
55
- case 'autocomplete': {
56
- const options: AutocompleteOption[] = (field.options ?? [])
57
- .filter((o): o is { label: string; value: string | number } => o.value !== null && o.value !== undefined)
58
- .map(o => ({ label: o.label, value: o.value }));
52
+ case 'autocomplete':
59
53
  return (
60
- <Autocomplete
61
- mode={field.autocompleteMode ?? 'client'}
62
- options={options}
63
- fetcher={field.fetcher}
64
- pageSize={field.pageSize}
65
- value={(controllerField.value as string | number | null) ?? null}
66
- onChange={(val) => handleChange(val)}
67
- placeholder={field.placeholder}
68
- searchPlaceholder={field.searchPlaceholder}
69
- renderOption={field.renderOption}
70
- disabled={field.disabled}
71
- className={baseProps.className}
54
+ <AutocompleteField
55
+ field={field}
56
+ control={control}
57
+ fieldPath={fieldPath}
58
+ value={controllerField.value}
59
+ onChange={handleChange}
60
+ className={baseClassName}
72
61
  />
73
62
  );
74
- }
75
63
  case 'text':
76
64
  case 'email':
77
65
  case 'password':
78
66
  return (
79
- <Input
80
- {...baseProps}
81
- type={field.type}
82
- value={controllerField.value || ''}
83
- onChange={e => handleChange(e.target.value)}
67
+ <TextField
68
+ field={field}
69
+ control={control}
70
+ fieldPath={fieldPath}
71
+ value={controllerField.value}
72
+ onChange={handleChange}
73
+ className={baseClassName}
84
74
  />
85
75
  );
86
-
87
76
  case 'number':
88
77
  return (
89
- <Input
90
- {...baseProps}
91
- type="number"
92
- value={controllerField.value || ''}
93
- onChange={e => handleChange(Number(e.target.value))}
78
+ <NumberField
79
+ field={field}
80
+ control={control}
81
+ fieldPath={fieldPath}
82
+ value={controllerField.value}
83
+ onChange={handleChange}
84
+ className={baseClassName}
94
85
  />
95
86
  );
96
-
97
87
  case 'textarea':
98
88
  return (
99
- <Textarea
100
- {...baseProps}
101
- value={controllerField.value || ''}
102
- onChange={e => handleChange(e.target.value)}
103
- rows={4}
89
+ <TextareaField
90
+ field={field}
91
+ control={control}
92
+ fieldPath={fieldPath}
93
+ value={controllerField.value}
94
+ onChange={handleChange}
95
+ className={baseClassName}
104
96
  />
105
97
  );
106
-
107
- case 'select': {
108
- const toUiValue = (val: unknown) => (val === null || val === undefined ? NULL_SENTINEL : String(val));
109
- const fromUiValue = (val: string) => {
110
- const match = field.options?.find(opt => toUiValue(opt.value) === val);
111
- return match ? match.value : null;
112
- };
98
+ case 'select':
113
99
  return (
114
- <Select
115
- value={toUiValue(controllerField.value)}
116
- onValueChange={val => handleChange(fromUiValue(val))}
117
- disabled={field.disabled}
118
- >
119
- <SelectTrigger className={baseProps.className}>
120
- <SelectValue placeholder={field.placeholder} />
121
- </SelectTrigger>
122
- <SelectContent>
123
- {field.options?.map(option => (
124
- <SelectItem key={toUiValue(option.value)} value={toUiValue(option.value)}>
125
- {option.label}
126
- </SelectItem>
127
- ))}
128
- </SelectContent>
129
- </Select>
100
+ <SelectField
101
+ field={field}
102
+ control={control}
103
+ fieldPath={fieldPath}
104
+ value={controllerField.value}
105
+ onChange={handleChange}
106
+ className={baseClassName}
107
+ />
130
108
  );
131
- }
132
-
133
- case 'checkbox': {
134
- const placement = field.labelPlacement ?? 'inline';
135
- if (placement === 'stacked') {
136
- const labelId = `${fieldPath}-label`;
137
- return (
138
- <div className="space-y-2">
139
- <Label id={labelId} className="text-sm font-medium">
140
- {field.label}
141
- {field.required && <span className="text-destructive ml-1">*</span>}
142
- </Label>
143
- <Checkbox
144
- aria-labelledby={labelId}
145
- id={fieldPath}
146
- checked={controllerField.value || false}
147
- onCheckedChange={handleChange}
148
- disabled={field.disabled}
149
- className={cn(error && 'border-destructive', field.className)}
150
- />
151
- </div>
152
- );
153
- }
154
- if (placement === 'hidden') {
155
- return (
156
- <Checkbox
157
- id={fieldPath}
158
- checked={controllerField.value || false}
159
- onCheckedChange={handleChange}
160
- disabled={field.disabled}
161
- className={cn(error && 'border-destructive', field.className)}
162
- />
163
- );
164
- }
165
- // inline (default)
109
+ case 'checkbox':
166
110
  return (
167
- <div className="flex items-center space-x-2">
168
- <Checkbox
169
- id={fieldPath}
170
- checked={controllerField.value || false}
171
- onCheckedChange={handleChange}
172
- disabled={field.disabled}
173
- className={cn(error && 'border-destructive', field.className)}
174
- />
175
- <Label htmlFor={fieldPath} className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
176
- {field.label}
177
- {field.required && <span className="text-destructive ml-1">*</span>}
178
- </Label>
179
- </div>
111
+ <CheckboxField
112
+ field={field}
113
+ control={control}
114
+ fieldPath={fieldPath}
115
+ value={controllerField.value}
116
+ onChange={handleChange}
117
+ className={baseClassName}
118
+ />
180
119
  );
181
- }
182
-
183
- case 'radio': {
184
- const toUiValue = (val: unknown) => (val === null || val === undefined ? NULL_SENTINEL : String(val));
185
- const fromUiValue = (val: string) => {
186
- const match = field.options?.find(opt => toUiValue(opt.value) === val);
187
- return match ? match.value : null;
188
- };
120
+ case 'switch':
189
121
  return (
190
- <RadioGroup
191
- value={toUiValue(controllerField.value)}
192
- onValueChange={val => handleChange(fromUiValue(val))}
193
- disabled={field.disabled}
194
- className={field.className}
195
- >
196
- {field.options?.map(option => (
197
- <div key={toUiValue(option.value)} className="flex items-center space-x-2">
198
- <RadioGroupItem value={toUiValue(option.value)} id={`${fieldPath}-${toUiValue(option.value)}`} />
199
- <Label htmlFor={`${fieldPath}-${toUiValue(option.value)}`}>{option.label}</Label>
200
- </div>
201
- ))}
202
- </RadioGroup>
122
+ <SwitchField
123
+ field={field}
124
+ control={control}
125
+ fieldPath={fieldPath}
126
+ value={controllerField.value}
127
+ onChange={handleChange}
128
+ className={baseClassName}
129
+ />
130
+ );
131
+ case 'radio':
132
+ return (
133
+ <RadioField
134
+ field={field}
135
+ control={control}
136
+ fieldPath={fieldPath}
137
+ value={controllerField.value}
138
+ onChange={handleChange}
139
+ className={baseClassName}
140
+ />
203
141
  );
204
- }
205
-
206
142
  case 'date':
207
143
  return (
208
- <Input
209
- {...baseProps}
210
- type="date"
211
- value={controllerField.value ? new Date(controllerField.value).toISOString().split('T')[0] : ''}
212
- onChange={e => handleChange(e.target.value ? new Date(e.target.value) : null)}
144
+ <DateField
145
+ field={field}
146
+ control={control}
147
+ fieldPath={fieldPath}
148
+ value={controllerField.value}
149
+ onChange={handleChange}
150
+ className={baseClassName}
213
151
  />
214
152
  );
215
-
216
153
  case 'file':
217
154
  return (
218
- <Input
219
- {...baseProps}
220
- type="file"
221
- onChange={e => handleChange(e.target.files?.[0] || null)}
155
+ <FileField
156
+ field={field}
157
+ control={control}
158
+ fieldPath={fieldPath}
159
+ value={controllerField.value}
160
+ onChange={handleChange}
161
+ className={baseClassName}
162
+ />
163
+ );
164
+ case 'object':
165
+ return (
166
+ <ObjectField
167
+ field={field}
168
+ control={control}
169
+ fieldPath={fieldPath}
170
+ value={controllerField.value}
171
+ onChange={handleChange}
172
+ className={baseClassName}
173
+ />
174
+ );
175
+ case 'array':
176
+ return (
177
+ <ArrayField
178
+ field={field}
179
+ control={control}
180
+ fieldPath={fieldPath}
181
+ value={controllerField.value}
182
+ onChange={handleChange}
183
+ className={baseClassName}
222
184
  />
223
185
  );
224
-
225
186
  default:
226
187
  return (
227
- <Input
228
- {...baseProps}
229
- value={controllerField.value || ''}
230
- onChange={e => handleChange(e.target.value)}
188
+ <TextField
189
+ field={field}
190
+ control={control}
191
+ fieldPath={fieldPath}
192
+ value={controllerField.value}
193
+ onChange={handleChange}
194
+ className={baseClassName}
231
195
  />
232
196
  );
233
197
  }
234
198
  };
235
199
 
236
- const renderObjectField = () => {
237
- if (!field.fields) return null;
238
-
239
- return (
240
- <Card className={field.className}>
241
- <CardHeader className="pb-3">
242
- <CardTitle className="text-base">{field.label}</CardTitle>
243
- {field.description && (
244
- <p className="text-sm text-muted-foreground">{field.description}</p>
245
- )}
246
- </CardHeader>
247
- <CardContent className="space-y-4">
248
- <div className="grid gap-4 md:grid-cols-2">
249
- {field.fields.map(subField => (
250
- <FormBuilderField
251
- key={subField.name}
252
- field={subField}
253
- control={control}
254
- parentPath={fieldPath}
255
- onChange={onChange}
256
- onFieldChange={onFieldChange}
257
- />
258
- ))}
259
- </div>
260
- </CardContent>
261
- </Card>
262
- );
263
- };
264
-
265
- const renderArrayField = () => {
266
- const { fields, append, remove } = useFieldArray({
267
- control,
268
- name: fieldPath,
269
- });
270
-
271
- const addItem = () => {
272
- if (field.fields && field.fields.length === 1) {
273
- // Single field array (e.g., array of strings)
274
- const defaultValue = field.fields[0].defaultValue || '';
275
- append(defaultValue);
276
- }
277
- else if (field.fields) {
278
- // Object array
279
- const defaultObject: Record<string, any> = {};
280
- field.fields.forEach((subField) => {
281
- defaultObject[subField.name] = subField.defaultValue || '';
282
- });
283
- append(defaultObject);
284
- }
285
- else {
286
- append('');
287
- }
288
- };
289
-
290
- return (
291
- <Card className={field.className}>
292
- <CardHeader className="pb-3">
293
- <div className="flex items-center justify-between">
294
- <div>
295
- <CardTitle className="text-base">{field.label}</CardTitle>
296
- {field.description && (
297
- <p className="text-sm text-muted-foreground">{field.description}</p>
298
- )}
299
- </div>
300
- <Button
301
- type="button"
302
- variant="outline"
303
- size="sm"
304
- onClick={addItem}
305
- disabled={field.disabled}
306
- >
307
- <Plus className="h-4 w-4 mr-1" />
308
- Add Item
309
- </Button>
310
- </div>
311
- </CardHeader>
312
- <CardContent className="space-y-4">
313
- {fields.length === 0 ? (
314
- <p className="text-sm text-muted-foreground text-center py-4">
315
- No items added yet. Click "Add Item" to get started.
316
- </p>
317
- ) : (
318
- fields.map((item, index) => (
319
- <Card key={item.id} className="relative">
320
- <CardHeader className="pb-3">
321
- <div className="flex items-center justify-between">
322
- <div className="flex items-center gap-2">
323
- <GripVertical className="h-4 w-4 text-muted-foreground" />
324
- <span className="text-sm font-medium">
325
- Item
326
- {index + 1}
327
- </span>
328
- </div>
329
- <Button
330
- type="button"
331
- variant="ghost"
332
- size="sm"
333
- onClick={() => remove(index)}
334
- disabled={field.disabled}
335
- >
336
- <Trash2 className="h-4 w-4" />
337
- </Button>
338
- </div>
339
- </CardHeader>
340
- <CardContent>
341
- {field.fields && field.fields.length === 1 ? (
342
- // Single field array
343
- <FormBuilderField
344
- field={{
345
- ...field.fields[0],
346
- name: field.fields[0].name,
347
- label: field.fields[0].label || 'Value',
348
- }}
349
- control={control}
350
- parentPath={`${fieldPath}.${index}`}
351
- onChange={onChange}
352
- />
353
- ) : field.fields ? (
354
- // Object array
355
- <div className="grid gap-4 md:grid-cols-2">
356
- {field.fields.map(subField => (
357
- <FormBuilderField
358
- key={subField.name}
359
- field={subField}
360
- control={control}
361
- parentPath={`${fieldPath}.${index}`}
362
- onChange={onChange}
363
- onFieldChange={onFieldChange}
364
- />
365
- ))}
366
- </div>
367
- ) : (
368
- // Fallback for arrays without field definitions
369
- <Input
370
- value={controllerField.value?.[index] || ''}
371
- onChange={(e) => {
372
- const newArray = [...(controllerField.value || [])];
373
- newArray[index] = e.target.value;
374
- handleChange(newArray);
375
- }}
376
- placeholder={`Item ${index + 1}`}
377
- disabled={field.disabled}
378
- />
379
- )}
380
- </CardContent>
381
- </Card>
382
- ))
383
- )}
384
- </CardContent>
385
- </Card>
386
- );
387
- };
388
-
389
- if (field.type === 'object') {
390
- return renderObjectField();
391
- }
392
-
393
- if (field.type === 'array') {
394
- return renderArrayField();
395
- }
396
-
397
- // For checkbox, label may be inline/stacked/hidden handled inside renderBasicField
398
- if (field.type === 'checkbox') {
200
+ // For checkbox/switch, label is handled inside the specific field component
201
+ if (field.type === 'checkbox' || field.type === 'switch') {
399
202
  return (
400
203
  <div className={cn('space-y-2', field.gridCols && `md:col-span-${field.gridCols}`)}>
401
- {renderBasicField()}
204
+ {renderField()}
402
205
  {field.description && (
403
206
  <p className="text-sm text-muted-foreground">{field.description}</p>
404
207
  )}
@@ -411,10 +214,10 @@ export function FormBuilderField({ field, control, onChange, onFieldChange, pare
411
214
 
412
215
  // Non-checkbox fields: support labelPlacement
413
216
  const placement = field.labelPlacement ?? 'stacked';
414
- if (placement === 'hidden') {
217
+ if (placement === 'hidden' || field.type === 'array') {
415
218
  return (
416
219
  <div className={cn('space-y-2', field.gridCols && `md:col-span-${field.gridCols}`)}>
417
- {renderBasicField()}
220
+ {renderField()}
418
221
  {field.description && (
419
222
  <p className="text-sm text-muted-foreground">{field.description}</p>
420
223
  )}
@@ -425,7 +228,7 @@ export function FormBuilderField({ field, control, onChange, onFieldChange, pare
425
228
  );
426
229
  }
427
230
 
428
- if (placement === 'inline') {
231
+ if (placement === 'inline' && field.type !== 'array') {
429
232
  return (
430
233
  <div className={cn('space-y-1', field.gridCols && `md:col-span-${field.gridCols}`)}>
431
234
  <div className="flex items-center gap-2">
@@ -433,7 +236,7 @@ export function FormBuilderField({ field, control, onChange, onFieldChange, pare
433
236
  {field.label}
434
237
  {field.required && <span className="text-destructive ml-1">*</span>}
435
238
  </Label>
436
- {renderBasicField()}
239
+ {renderField()}
437
240
  </div>
438
241
  {field.description && (
439
242
  <p className="text-sm text-muted-foreground">{field.description}</p>
@@ -452,7 +255,7 @@ export function FormBuilderField({ field, control, onChange, onFieldChange, pare
452
255
  {field.label}
453
256
  {field.required && <span className="text-destructive ml-1">*</span>}
454
257
  </Label>
455
- {renderBasicField()}
258
+ {renderField()}
456
259
  {field.description && (
457
260
  <p className="text-sm text-muted-foreground">{field.description}</p>
458
261
  )}