Skip to content

Commit ee38398

Browse files
committed
feat: add widget components (TextField, NumberField, BooleanField, SelectField, DateField) and update exports in index
1 parent edbbed5 commit ee38398

File tree

10 files changed

+264
-2
lines changed

10 files changed

+264
-2
lines changed

packages/f

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
lds }
2+
3+
// Cast for rowdW return <spanr> }
4+
5+
// Cast fpe
6+
ies
7+
// Cast for rows le
8+
/nte
9+
// Cast fpe
10+
ies
11+
// Cast for rows Se ies
12+
// C} f / ' const rot = const rows po if (rows && rows > 1) {
13+
rsN return (
14+
<Textpa <Tid rsN return (
15+
'; <Textpa Se cly) className={pro }}
16+
/>
17+
);
18+
}
19+
20+
returned cly) className={= />
21+
);
22+
}
23+
24+
returned data).options }
25+
26+
];
27+
28+
i />
29+
);
30+
}
31+
32+
return (
33+
ss );
34+
(o) => o.valu }
35+
36+
v
37+
ue) ss )urn <span cla
38+
/>
39+
="text-sm">{op disnF disa-2 disnF disabled={readonly}fi clasac className={propsialexport funcm
40+
expo}
41+
export function TextField({ value, onChanops if (readonly) {
42+
return export functro return <span classld return export functro return <span className="text-sct>{ }
43+
44+
// Cast fbel>
45+
</div>
46+
);
47+
}
48+
EOF
49+
50+
cat > packages/f
51+
lds }
52+
53+
// Cast tem key={ </div>
54+
)va );
55+
}
56+
EOon.value}EO EOon.value}EO n.label}
57+
</SelectItem>
58+
))}
59+
</SelectContent>
60+
</Select>
61+
);
62+
}
63+
EOF
64+
65+
cat > packages/fields/src/widgets/DateField.tsx <<EOF
66+
import React from 'react';
67+
import { Input } from '@object-ui/components';
68+
import { FieldWidgetProps } from './types';
69+
70+
export function DateField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<string>) {
71+
if (readonly) {
72+
return <span className="text-sm">{value ? new Date(value).toLocaleDateString() : '-'}</span>;
73+
}
74+
75+
return (
76+
<Input
77+
type="date"
78+
value={value || ''}
79+
onChange={(e) => onChange(e.target.value)}
80+
disabled={readonly}
81+
className={props.className}
82+
/>
83+
);
84+
}
85+
EOF

packages/fields/src/index.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,3 +713,10 @@ export function evaluateCondition(condition: any, formData: any): boolean {
713713
// Default to true if condition format is unknown
714714
return true;
715715
}
716+
717+
export * from './widgets/types';
718+
export * from './widgets/TextField';
719+
export * from './widgets/NumberField';
720+
export * from './widgets/BooleanField';
721+
export * from './widgets/SelectField';
722+
export * from './widgets/DateField';
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React from 'react';
2+
import { Switch, Checkbox, Label } from '@object-ui/components';
3+
import { FieldWidgetProps } from './types';
4+
5+
export function BooleanField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<boolean>) {
6+
if (readonly) {
7+
return <span className="text-sm">{value ? 'Yes' : 'No'}</span>;
8+
}
9+
10+
// Use simple type assertion for arbitrary custom properties not in BaseFieldMetadata
11+
const widget = (field as any).widget;
12+
13+
if (widget === 'checkbox') {
14+
return (
15+
<div className="flex items-center space-x-2">
16+
<Checkbox
17+
id={field.name}
18+
checked={!!value}
19+
onCheckedChange={(checked) => onChange(!!checked)}
20+
disabled={readonly}
21+
className={props.className}
22+
/>
23+
<Label htmlFor={field.name}>{field.label}</Label>
24+
</div>
25+
)
26+
}
27+
28+
return (
29+
<div className="flex items-center space-x-2">
30+
<Switch
31+
id={field.name}
32+
checked={!!value}
33+
onCheckedChange={onChange}
34+
disabled={readonly}
35+
className={props.className}
36+
/>
37+
<Label htmlFor={field.name}>{field.label}</Label>
38+
</div>
39+
);
40+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react';
2+
import { Input } from '@object-ui/components';
3+
import { FieldWidgetProps } from './types';
4+
5+
export function DateField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<string>) {
6+
if (readonly) {
7+
return <span className="text-sm">{value ? new Date(value).toLocaleDateString() : '-'}</span>;
8+
}
9+
10+
return (
11+
<Input
12+
type="date"
13+
value={value || ''}
14+
onChange={(e) => onChange(e.target.value)}
15+
disabled={readonly}
16+
className={props.className}
17+
/>
18+
);
19+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import { Input } from '@object-ui/components';
3+
import { NumberFieldMetadata } from '@object-ui/types';
4+
import { FieldWidgetProps } from './types';
5+
6+
export function NumberField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<number>) {
7+
if (readonly) {
8+
return <span className="text-sm">{value ?? '-'}</span>;
9+
}
10+
11+
const precision = (field as unknown as NumberFieldMetadata).precision;
12+
13+
return (
14+
<Input
15+
type="number"
16+
value={value ?? ''}
17+
onChange={(e) => {
18+
const val = e.target.value;
19+
onChange(val === '' ? (null as any) : Number(val));
20+
}}
21+
placeholder={field.placeholder}
22+
disabled={readonly}
23+
step={precision ? Math.pow(10, -precision) : 'any'}
24+
className={props.className}
25+
/>
26+
);
27+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React from 'react';
2+
import {
3+
Select,
4+
SelectContent,
5+
SelectItem,
6+
SelectTrigger,
7+
SelectValue
8+
} from '@object-ui/components';
9+
import { SelectFieldMetadata } from '@object-ui/types';
10+
import { FieldWidgetProps } from './types';
11+
12+
export function SelectField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<string>) {
13+
const options = (field as unknown as SelectFieldMetadata).options || [];
14+
15+
if (readonly) {
16+
const option = options.find((o) => o.value === value);
17+
return <span className="text-sm">{option?.label || value || '-'}</span>;
18+
}
19+
20+
return (
21+
<Select
22+
value={value}
23+
onValueChange={onChange}
24+
disabled={readonly}
25+
>
26+
<SelectTrigger className={props.className}>
27+
<SelectValue placeholder={field.placeholder || "Select an option"} />
28+
</SelectTrigger>
29+
<SelectContent>
30+
{options.map((option) => (
31+
<SelectItem key={option.value} value={option.value}>
32+
{option.label}
33+
</SelectItem>
34+
))}
35+
</SelectContent>
36+
</Select>
37+
);
38+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react';
2+
import { Input, Textarea } from '@object-ui/components';
3+
import { TextareaFieldMetadata } from '@object-ui/types';
4+
import { FieldWidgetProps } from './types';
5+
6+
export function TextField({ value, onChange, field, readonly, ...props }: FieldWidgetProps<string>) {
7+
if (readonly) {
8+
return <span className="text-sm">{value || '-'}</span>;
9+
}
10+
11+
// Cast for rows property
12+
const rows = (field as unknown as TextareaFieldMetadata).rows;
13+
14+
if (rows && rows > 1) {
15+
return (
16+
<Textarea
17+
value={value || ''}
18+
onChange={(e) => onChange(e.target.value)}
19+
placeholder={field.placeholder}
20+
disabled={readonly}
21+
className={props.className}
22+
/>
23+
);
24+
}
25+
26+
return (
27+
<Input
28+
type={field.type === 'password' ? 'password' : 'text'}
29+
value={value || ''}
30+
onChange={(e) => onChange(e.target.value)}
31+
placeholder={field.placeholder}
32+
disabled={readonly}
33+
className={props.className}
34+
/>
35+
);
36+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { FieldMetadata } from '@object-ui/types';
2+
3+
export type FieldWidgetProps<T = any> = {
4+
value: T;
5+
onChange: (val: T) => void;
6+
// Use a looser type for field to avoid complex circular dependencies for now
7+
field: FieldMetadata;
8+
readonly?: boolean;
9+
className?: string;
10+
errorMessage?: string;
11+
}

packages/fields/tsconfig.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"extends": "../../tsconfig.json",
33
"compilerOptions": {
44
"outDir": "dist",
5-
"rootDir": "src",
65
"jsx": "react-jsx"
76
},
87
"include": ["src"]

packages/fields/vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default defineConfig({
1212
],
1313
build: {
1414
lib: {
15-
entry: path.resolve(__dirname, 'src/index.ts'),
15+
entry: path.resolve(__dirname, 'src/index.tsx'),
1616
name: 'ObjectUIFields',
1717
formats: ['es', 'cjs'],
1818
fileName: (format) => `index.${format === 'es' ? 'js' : 'cjs'}`,

0 commit comments

Comments
 (0)