/** * Reusable memoized field for settings: TextControl or SelectControl with optional error. */ import { memo } from '@wordpress/element'; import type { ReactNode } from 'react'; import { TextControl, SelectControl } from '@wordpress/components'; export interface SettingsFieldSelectOption { value: string; label: string; } interface SettingsFieldTextProps { label: string; value: string; onChange: (value: string) => void; error?: string; description?: ReactNode; type?: 'text' | 'email' | 'number'; disabled?: boolean; min?: number; max?: number; step?: number; required?: boolean; } interface SettingsFieldSelectProps { label: string; value: string; onChange: (value: string) => void; options: SettingsFieldSelectOption[]; error?: string; description?: ReactNode; disabled?: boolean; required?: boolean; } type SettingsFieldProps = | ({ kind: 'text' } & SettingsFieldTextProps) | ({ kind: 'select' } & SettingsFieldSelectProps); function SettingsFieldInner(props: SettingsFieldProps) { const { label, value, onChange, error } = props; const required = 'required' in props ? props.required : false; const displayLabel = required ? `${label} *` : label; const help = error ?? undefined; const description = props.description ?? null; if (props.kind === 'select') { return (
onChange(v ?? '')} help={help} disabled={props.disabled} /> {description && (

{description}

)}
); } return (
onChange(v ?? '')} help={help} type={props.type ?? 'text'} disabled={props.disabled} min={props.min} max={props.max} step={props.step} /> {description && (

{description}

)}
); } export const SettingsField = memo(SettingsFieldInner);