feat(plugin-form-builder): radio field (#11716)
### What? A field for input radio Demo: <img width="1320" alt="Screenshot 2025-03-15 at 6 54 51 AM" src="https://github.com/user-attachments/assets/47744e3f-e1ca-4596-bc7c-09f7b2d42c5b" /> --- UI code example, using shadcn/ui: ```tsx import type { SelectField } from '@payloadcms/plugin-form-builder/types' import type { Control, FieldErrorsImpl } from 'react-hook-form' import { Label } from '@/components/ui/label' import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group' import React from 'react' import { Controller } from 'react-hook-form' import { Error } from '../Error' import { Width } from '../Width' export const Radio: React.FC< SelectField & { control: Control errors: Partial<FieldErrorsImpl> } > = ({ name, control, errors, label, options, required, width, defaultValue }) => { return ( <Width width={width}> <Label htmlFor={name}>{label}</Label> <Controller control={control} defaultValue={defaultValue} name={name} render={({ field: { onChange, value } }) => { return ( <RadioGroup onValueChange={(val) => onChange(val)} value={value} className="space-y-2"> {options.map(({ label, value }) => { const id = `${name}-${value}` return ( <div key={value} className="flex items-center space-x-2"> <RadioGroupItem value={value} id={id} /> <Label htmlFor={id}>{label}</Label> </div> ) })} </RadioGroup> ) }} rules={{ required }} /> {required && errors[name] && <Error />} </Width> ) } ``` UI demo: <img width="651" alt="Screenshot 2025-03-15 at 7 04 37 AM" src="https://github.com/user-attachments/assets/f3922489-8e62-4464-b48c-8425735421f5" /> Co-authored-by: Pan <kpkong@hk01.com>
This commit is contained in:
@@ -28,6 +28,95 @@ const width: Field = {
|
|||||||
label: 'Field Width (percentage)',
|
label: 'Field Width (percentage)',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const placeholder: Field = {
|
||||||
|
name: 'placeholder',
|
||||||
|
type: 'text',
|
||||||
|
label: 'Placeholder',
|
||||||
|
}
|
||||||
|
|
||||||
|
const Radio: Block = {
|
||||||
|
slug: 'radio',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'row',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
...name,
|
||||||
|
admin: {
|
||||||
|
width: '50%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...label,
|
||||||
|
admin: {
|
||||||
|
width: '50%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'row',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
...width,
|
||||||
|
admin: {
|
||||||
|
width: '50%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'defaultValue',
|
||||||
|
type: 'text',
|
||||||
|
admin: {
|
||||||
|
width: '50%',
|
||||||
|
},
|
||||||
|
label: 'Default Value',
|
||||||
|
localized: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'options',
|
||||||
|
type: 'array',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'row',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'label',
|
||||||
|
type: 'text',
|
||||||
|
admin: {
|
||||||
|
width: '50%',
|
||||||
|
},
|
||||||
|
label: 'Label',
|
||||||
|
localized: true,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'value',
|
||||||
|
type: 'text',
|
||||||
|
admin: {
|
||||||
|
width: '50%',
|
||||||
|
},
|
||||||
|
label: 'Value',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: 'Radio Attribute Options',
|
||||||
|
labels: {
|
||||||
|
plural: 'Options',
|
||||||
|
singular: 'Option',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required,
|
||||||
|
],
|
||||||
|
labels: {
|
||||||
|
plural: 'Radio Fields',
|
||||||
|
singular: 'Radio',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const Select: Block = {
|
const Select: Block = {
|
||||||
slug: 'select',
|
slug: 'select',
|
||||||
fields: [
|
fields: [
|
||||||
@@ -68,6 +157,14 @@ const Select: Block = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'row',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
...placeholder,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'options',
|
name: 'options',
|
||||||
type: 'array',
|
type: 'array',
|
||||||
@@ -576,6 +673,7 @@ export const fields = {
|
|||||||
message: Message,
|
message: Message,
|
||||||
number: Number,
|
number: Number,
|
||||||
payment: Payment,
|
payment: Payment,
|
||||||
|
radio: Radio,
|
||||||
select: Select,
|
select: Select,
|
||||||
state: State,
|
state: State,
|
||||||
text: Text,
|
text: Text,
|
||||||
|
|||||||
@@ -97,6 +97,19 @@ export interface SelectField {
|
|||||||
label?: string
|
label?: string
|
||||||
name: string
|
name: string
|
||||||
options: SelectFieldOption[]
|
options: SelectFieldOption[]
|
||||||
|
placeholder?: string
|
||||||
|
required?: boolean
|
||||||
|
width?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RadioField {
|
||||||
|
blockName?: string
|
||||||
|
blockType: 'radio'
|
||||||
|
defaultValue?: string
|
||||||
|
label?: string
|
||||||
|
name: string
|
||||||
|
options: SelectFieldOption[]
|
||||||
|
placeholder?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
width?: number
|
width?: number
|
||||||
}
|
}
|
||||||
@@ -175,6 +188,7 @@ export type FormFieldBlock =
|
|||||||
| EmailField
|
| EmailField
|
||||||
| MessageField
|
| MessageField
|
||||||
| PaymentField
|
| PaymentField
|
||||||
|
| RadioField
|
||||||
| SelectField
|
| SelectField
|
||||||
| StateField
|
| StateField
|
||||||
| TextAreaField
|
| TextAreaField
|
||||||
|
|||||||
Reference in New Issue
Block a user