Skip to content

Commit 5872865

Browse files
authored
Merge pull request #253 from objectstack-ai/copilot/develop-all-ui-components
2 parents 0376a2c + 12ce9c1 commit 5872865

14 files changed

Lines changed: 1503 additions & 3 deletions

packages/fields/src/fields.stories.tsx

Lines changed: 189 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,22 @@ import {
2121
FileField,
2222
LocationField,
2323
FormulaField,
24-
SummaryField
24+
SummaryField,
25+
RichTextField,
26+
ImageField,
27+
ObjectField,
28+
VectorField,
29+
GridField,
30+
ColorField,
31+
SliderField,
32+
RatingField,
33+
CodeField,
34+
AvatarField,
35+
AddressField,
36+
GeolocationField,
37+
SignatureField,
38+
QRCodeField,
39+
MasterDetailField
2540
} from './index';
2641
import { FieldMetadata } from '@object-ui/types';
2742

@@ -376,3 +391,176 @@ export const ReadOnly: Story = {
376391
</div>
377392
)
378393
};
394+
395+
// --- New Widgets ---
396+
397+
export const RichText: Story = {
398+
render: () => (
399+
<FieldWrapper
400+
Component={RichTextField}
401+
field={{ label: 'Description', type: 'html' }}
402+
initialValue="<p><b>Rich</b> text content...</p>"
403+
/>
404+
)
405+
};
406+
407+
export const Image: Story = {
408+
render: () => (
409+
<FieldWrapper
410+
Component={ImageField}
411+
field={{ label: 'Banner', type: 'image' }}
412+
initialValue="https://placehold.co/600x400"
413+
/>
414+
)
415+
};
416+
417+
export const Color: Story = {
418+
render: () => (
419+
<FieldWrapper
420+
Component={ColorField}
421+
field={{ label: 'Theme Color', type: 'color' }}
422+
initialValue="#3b82f6"
423+
/>
424+
)
425+
};
426+
427+
export const Slider: Story = {
428+
render: () => (
429+
<FieldWrapper
430+
Component={SliderField}
431+
field={{ label: 'Opacity', type: 'slider', min: 0, max: 100 } as any}
432+
initialValue={75}
433+
/>
434+
)
435+
};
436+
437+
export const Rating: Story = {
438+
render: () => (
439+
<FieldWrapper
440+
Component={RatingField}
441+
field={{ label: 'Score', type: 'rating', max: 5 } as any}
442+
initialValue={4}
443+
/>
444+
)
445+
};
446+
447+
export const Code: Story = {
448+
render: () => (
449+
<FieldWrapper
450+
Component={CodeField}
451+
field={{ label: 'Config JSON', type: 'code' }}
452+
initialValue='{ "debug": true }'
453+
/>
454+
)
455+
};
456+
457+
export const Avatar: Story = {
458+
render: () => (
459+
<FieldWrapper
460+
Component={AvatarField}
461+
field={{ label: 'Profile', type: 'avatar' }}
462+
initialValue="https://github.com/shadcn.png"
463+
/>
464+
)
465+
};
466+
467+
export const Signature: Story = {
468+
render: () => (
469+
<FieldWrapper
470+
Component={SignatureField}
471+
field={{ label: 'Sign Here', type: 'signature' }}
472+
initialValue=""
473+
/>
474+
)
475+
};
476+
477+
export const QRCode: Story = {
478+
render: () => (
479+
<FieldWrapper
480+
Component={QRCodeField}
481+
field={{ label: 'Scan Me', type: 'qrcode' }}
482+
initialValue="https://objectui.org"
483+
/>
484+
)
485+
};
486+
487+
export const Address: Story = {
488+
render: () => (
489+
<FieldWrapper
490+
Component={AddressField}
491+
field={{ label: 'Shipping Address', type: 'address' }}
492+
initialValue={{ street: '123 Main St', city: 'Anytown', country: 'USA' }}
493+
/>
494+
)
495+
};
496+
497+
export const Geolocation: Story = {
498+
render: () => (
499+
<FieldWrapper
500+
Component={GeolocationField}
501+
field={{ label: 'Location', type: 'geolocation' }}
502+
initialValue={{ lat: 37.7749, lng: -122.4194 }}
503+
/>
504+
)
505+
};
506+
507+
export const Object: Story = {
508+
render: () => (
509+
<FieldWrapper
510+
Component={ObjectField}
511+
field={{
512+
label: 'Metadata',
513+
type: 'object',
514+
fields: [
515+
{ name: 'key', type: 'text', label: 'Key' },
516+
{ name: 'value', type: 'text', label: 'Value' }
517+
]
518+
} as any}
519+
initialValue={{ key: 'theme', value: 'dark' }}
520+
/>
521+
)
522+
};
523+
524+
export const Grid: Story = {
525+
render: () => (
526+
<FieldWrapper
527+
Component={GridField}
528+
field={{
529+
label: 'Order Items',
530+
type: 'grid',
531+
columns: [
532+
{ field: 'item', label: 'Item' },
533+
{ field: 'qty', label: 'Qty' }
534+
]
535+
} as any}
536+
initialValue={[
537+
{ item: 'Apple', qty: 2 },
538+
{ item: 'Banana', qty: 5 }
539+
]}
540+
/>
541+
)
542+
};
543+
544+
export const MasterDetail: Story = {
545+
render: () => (
546+
<FieldWrapper
547+
Component={MasterDetailField}
548+
field={{
549+
label: 'Line Items',
550+
type: 'master_detail',
551+
reference_to: 'products'
552+
} as any}
553+
initialValue={[]}
554+
/>
555+
)
556+
};
557+
558+
export const Vector: Story = {
559+
render: () => (
560+
<FieldWrapper
561+
Component={VectorField}
562+
field={{ label: 'Embedding', type: 'vector' }}
563+
initialValue={[0.1, 0.2, 0.3, 0.4]}
564+
/>
565+
)
566+
};

packages/fields/src/index.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,17 @@ import { UserField } from './widgets/UserField';
741741
import { ObjectField } from './widgets/ObjectField';
742742
import { VectorField } from './widgets/VectorField';
743743
import { GridField } from './widgets/GridField';
744+
// New widgets according to @objectstack/spec
745+
import { ColorField } from './widgets/ColorField';
746+
import { SliderField } from './widgets/SliderField';
747+
import { RatingField } from './widgets/RatingField';
748+
import { CodeField } from './widgets/CodeField';
749+
import { AvatarField } from './widgets/AvatarField';
750+
import { AddressField } from './widgets/AddressField';
751+
import { GeolocationField } from './widgets/GeolocationField';
752+
import { SignatureField } from './widgets/SignatureField';
753+
import { QRCodeField } from './widgets/QRCodeField';
754+
import { MasterDetailField } from './widgets/MasterDetailField';
744755

745756
// Create wrapper renderers for field widgets to work with ComponentDemo
746757
function createFieldRenderer(FieldWidget: React.ComponentType<any>) {
@@ -822,7 +833,7 @@ export function registerFields() {
822833
ComponentRegistry.register('markdown', createFieldRenderer(RichTextField));
823834
ComponentRegistry.register('html', createFieldRenderer(RichTextField));
824835
ComponentRegistry.register('lookup', createFieldRenderer(LookupField));
825-
ComponentRegistry.register('master_detail', createFieldRenderer(LookupField));
836+
ComponentRegistry.register('master_detail', createFieldRenderer(MasterDetailField));
826837

827838
// File fields
828839
ComponentRegistry.register('file', createFieldRenderer(FileField));
@@ -845,6 +856,17 @@ export function registerFields() {
845856
ComponentRegistry.register('vector', createFieldRenderer(VectorField));
846857
ComponentRegistry.register('grid', createFieldRenderer(GridField));
847858

859+
// NEW: Additional field types from @objectstack/spec
860+
ComponentRegistry.register('color', createFieldRenderer(ColorField));
861+
ComponentRegistry.register('slider', createFieldRenderer(SliderField));
862+
ComponentRegistry.register('rating', createFieldRenderer(RatingField));
863+
ComponentRegistry.register('code', createFieldRenderer(CodeField));
864+
ComponentRegistry.register('avatar', createFieldRenderer(AvatarField));
865+
ComponentRegistry.register('address', createFieldRenderer(AddressField));
866+
ComponentRegistry.register('geolocation', createFieldRenderer(GeolocationField));
867+
ComponentRegistry.register('signature', createFieldRenderer(SignatureField));
868+
ComponentRegistry.register('qrcode', createFieldRenderer(QRCodeField));
869+
848870
// Register with field: prefix for explicit field widgets
849871
ComponentRegistry.register('field:text', TextField);
850872
ComponentRegistry.register('field:textarea', TextAreaField);
@@ -864,6 +886,18 @@ export function registerFields() {
864886
ComponentRegistry.register('field:location', LocationField);
865887
ComponentRegistry.register('field:user', UserField);
866888
ComponentRegistry.register('field:object', ObjectField);
889+
890+
// NEW: field: prefix registrations for new widgets
891+
ComponentRegistry.register('field:color', ColorField);
892+
ComponentRegistry.register('field:slider', SliderField);
893+
ComponentRegistry.register('field:rating', RatingField);
894+
ComponentRegistry.register('field:code', CodeField);
895+
ComponentRegistry.register('field:avatar', AvatarField);
896+
ComponentRegistry.register('field:address', AddressField);
897+
ComponentRegistry.register('field:geolocation', GeolocationField);
898+
ComponentRegistry.register('field:signature', SignatureField);
899+
ComponentRegistry.register('field:qrcode', QRCodeField);
900+
ComponentRegistry.register('field:master_detail', MasterDetailField);
867901
}
868902

869903
export * from './widgets/types';
@@ -893,3 +927,14 @@ export * from './widgets/UserField';
893927
export * from './widgets/ObjectField';
894928
export * from './widgets/VectorField';
895929
export * from './widgets/GridField';
930+
// New widgets according to @objectstack/spec
931+
export * from './widgets/ColorField';
932+
export * from './widgets/SliderField';
933+
export * from './widgets/RatingField';
934+
export * from './widgets/CodeField';
935+
export * from './widgets/AvatarField';
936+
export * from './widgets/AddressField';
937+
export * from './widgets/GeolocationField';
938+
export * from './widgets/SignatureField';
939+
export * from './widgets/QRCodeField';
940+
export * from './widgets/MasterDetailField';

0 commit comments

Comments
 (0)