Skip to content

Commit e87b9a1

Browse files
committed
fix: update field components to use schema for configuration and improve placeholder handling
1 parent 8139075 commit e87b9a1

25 files changed

Lines changed: 72 additions & 53 deletions

packages/fields/src/widgets/AvatarField.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import { FieldWidgetProps } from './types';
77
* Avatar field widget - provides an avatar/profile picture uploader
88
* Supports image URLs or file uploads
99
*/
10-
export function AvatarField({ value, onChange, field, readonly }: FieldWidgetProps<string>) {
10+
export function AvatarField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<string>) {
1111
const [isHovered, setIsHovered] = React.useState(false);
1212
const fileInputRef = React.useRef<HTMLInputElement>(null);
13+
14+
const avatarField = (field || (props as any).schema) as any;
1315

1416
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
1517
const file = event.target.files?.[0];
@@ -41,7 +43,7 @@ export function AvatarField({ value, onChange, field, readonly }: FieldWidgetPro
4143

4244
// Extract initials for fallback
4345
const getInitials = (): string => {
44-
const name = (field as any).defaultName || field.label || 'User';
46+
const name = avatarField?.defaultName || avatarField?.label || 'User';
4547
return name
4648
.split(' ')
4749
.map((word: string) => word[0])
@@ -53,7 +55,7 @@ export function AvatarField({ value, onChange, field, readonly }: FieldWidgetPro
5355
if (readonly) {
5456
return (
5557
<Avatar className="w-16 h-16">
56-
{value && <AvatarImage src={value} alt={field.label} />}
58+
{value && <AvatarImage src={value} alt={avatarField?.label} />}
5759
<AvatarFallback>{getInitials()}</AvatarFallback>
5860
</Avatar>
5961
);
@@ -67,7 +69,7 @@ export function AvatarField({ value, onChange, field, readonly }: FieldWidgetPro
6769
onMouseLeave={() => setIsHovered(false)}
6870
>
6971
<Avatar className="w-16 h-16">
70-
{value && <AvatarImage src={value} alt={field.label} />}
72+
{value && <AvatarImage src={value} alt={avatarField?.label} />}
7173
<AvatarFallback>{getInitials()}</AvatarFallback>
7274
</Avatar>
7375
{!readonly && isHovered && value && (

packages/fields/src/widgets/BooleanField.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,37 @@ export function BooleanField({ value, onChange, field, readonly, ...props }: Fie
77
return <span className="text-sm">{value ? 'Yes' : 'No'}</span>;
88
}
99

10+
const config = (field || (props as any).schema) as any;
1011
// Use simple type assertion for arbitrary custom properties not in BaseFieldMetadata
11-
const widget = (field as any).widget;
12+
const widget = config?.widget;
13+
const id = config?.name || `boolean-field-${Math.random().toString(36).substr(2, 9)}`;
14+
const label = config?.label || 'Checkbox';
1215

1316
if (widget === 'checkbox') {
1417
return (
1518
<div className="flex items-center space-x-2">
1619
<Checkbox
17-
id={field.name}
20+
id={id}
1821
checked={!!value}
1922
onCheckedChange={(checked) => onChange(!!checked)}
2023
disabled={readonly}
2124
className={props.className}
2225
/>
23-
<Label htmlFor={field.name}>{field.label}</Label>
26+
<Label htmlFor={id}>{label}</Label>
2427
</div>
2528
)
2629
}
2730

2831
return (
2932
<div className="flex items-center space-x-2">
3033
<Switch
31-
id={field.name}
34+
id={id}
3235
checked={!!value}
3336
onCheckedChange={onChange}
3437
disabled={readonly}
3538
className={props.className}
3639
/>
37-
<Label htmlFor={field.name}>{field.label}</Label>
40+
<Label htmlFor={id}>{label}</Label>
3841
</div>
3942
);
4043
}

packages/fields/src/widgets/CodeField.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import { FieldWidgetProps } from './types';
88
* For advanced code editing, use the @object-ui/plugin-editor component
99
*/
1010
export function CodeField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<string>) {
11+
const config = field || (props as any).schema;
1112
// Get code-specific configuration from field metadata
12-
const language = (field as any).language ?? 'javascript';
13+
const language = (config as any)?.language ?? 'javascript';
1314

1415
if (readonly) {
1516
return (
@@ -23,7 +24,7 @@ export function CodeField({ value, onChange, field, readonly, ...props }: FieldW
2324
<Textarea
2425
value={value || ''}
2526
onChange={(e) => onChange(e.target.value)}
26-
placeholder={field.placeholder || `// Write ${language} code here...`}
27+
placeholder={config?.placeholder || `// Write ${language} code here...`}
2728
disabled={readonly}
2829
className={`font-mono text-sm ${props.className}`}
2930
rows={12}

packages/fields/src/widgets/ColorField.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { FieldWidgetProps } from './types';
77
* Supports hex color values (e.g., #ff0000)
88
*/
99
export function ColorField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<string>) {
10+
const colorField = (field || (props as any).schema) as any;
11+
1012
if (readonly) {
1113
return (
1214
<div className="flex items-center gap-2">
@@ -32,7 +34,7 @@ export function ColorField({ value, onChange, field, readonly, ...props }: Field
3234
type="text"
3335
value={value || ''}
3436
onChange={(e) => onChange(e.target.value)}
35-
placeholder={field.placeholder || '#000000'}
37+
placeholder={colorField?.placeholder || '#000000'}
3638
disabled={readonly}
3739
className={props.className}
3840
pattern="^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"

packages/fields/src/widgets/CurrencyField.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function formatCurrency(value: number, currency: string = 'USD'): string {
1717
}
1818

1919
export function CurrencyField({ value, onChange, field, readonly, errorMessage, ...props }: FieldWidgetProps<number>) {
20-
const currencyField = field as any;
20+
const currencyField = (field || (props as any).schema) as any;
2121
const currency = currencyField?.currency || 'USD';
2222
const precision = currencyField?.precision ?? 2;
2323

@@ -51,7 +51,7 @@ export function CurrencyField({ value, onChange, field, readonly, errorMessage,
5151
onChange(val as any);
5252
}}
5353
onBlur={handleBlur}
54-
placeholder={field?.placeholder || '0.00'}
54+
placeholder={currencyField?.placeholder || '0.00'}
5555
disabled={readonly}
5656
className={`pl-8 ${props.className || ''}`}
5757
step={Math.pow(10, -precision).toFixed(precision)}

packages/fields/src/widgets/EmailField.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Input } from '@object-ui/components';
33
import { FieldWidgetProps } from './types';
44

55
export function EmailField({ value, onChange, field, readonly, errorMessage, ...props }: FieldWidgetProps<string>) {
6+
const config = field || (props as any).schema;
67
if (readonly) {
78
if (!value) return <span className="text-sm">-</span>;
89
return (
@@ -20,7 +21,7 @@ export function EmailField({ value, onChange, field, readonly, errorMessage, ...
2021
type="email"
2122
value={value || ''}
2223
onChange={(e) => onChange(e.target.value)}
23-
placeholder={field.placeholder || 'email@example.com'}
24+
placeholder={config?.placeholder || 'email@example.com'}
2425
disabled={readonly}
2526
className={props.className}
2627
aria-invalid={!!errorMessage}

packages/fields/src/widgets/FileField.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { FieldWidgetProps } from './types';
55

66
export function FileField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<any>) {
77
const inputRef = useRef<HTMLInputElement>(null);
8-
const fileField = field as any;
9-
const multiple = fileField.multiple || false;
10-
const accept = fileField.accept ? fileField.accept.join(',') : undefined;
8+
const fileField = (field || (props as any).schema) as any;
9+
const multiple = fileField?.multiple || false;
10+
const accept = fileField?.accept ? fileField.accept.join(',') : undefined;
1111

1212
if (readonly) {
1313
if (!value) return <span className="text-sm">-</span>;

packages/fields/src/widgets/FormulaField.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { FieldWidgetProps } from './types';
66
* Values are computed on the backend and cannot be edited
77
*/
88
export function FormulaField({ value, field, ...props }: FieldWidgetProps<any>) {
9-
const formulaField = field as any;
10-
const returnType = formulaField.return_type || 'text';
9+
const formulaField = (field || (props as any).schema) as any;
10+
const returnType = formulaField?.return_type || 'text';
1111

1212
// Format based on return type
1313
let displayValue = '-';

packages/fields/src/widgets/GridField.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { FieldWidgetProps } from './types';
77
* For full editing capabilities, use the grid plugin
88
*/
99
export function GridField({ value, field, readonly, ...props }: FieldWidgetProps<any[]>) {
10-
const gridField = field as any;
11-
const columns = gridField.columns || [];
10+
const gridField = (field || (props as any).schema) as any;
11+
const columns = gridField?.columns || [];
1212

1313
if (!value || !Array.isArray(value)) {
1414
return <span className="text-sm text-gray-500">-</span>;

packages/fields/src/widgets/ImageField.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { FieldWidgetProps } from './types';
55

66
export function ImageField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<any>) {
77
const inputRef = useRef<HTMLInputElement>(null);
8-
const imageField = field as any;
9-
const multiple = imageField.multiple || false;
10-
const accept = imageField.accept ? imageField.accept.join(',') : 'image/*';
8+
const imageField = (field || (props as any).schema) as any;
9+
const multiple = imageField?.multiple || false;
10+
const accept = imageField?.accept ? imageField.accept.join(',') : 'image/*';
1111

1212
if (readonly) {
1313
if (!value) return <span className="text-sm">-</span>;

0 commit comments

Comments
 (0)