// Custom @rjsf theme for vibe_erp. // // Applies the same Tailwind CSS classes used throughout the existing // SPA so that metadata-driven forms blend in seamlessly with the // hand-coded pages. import type { BaseInputTemplateProps, ErrorListProps, FieldTemplateProps, ObjectFieldTemplateProps, SubmitButtonProps, RJSFSchema, StrictRJSFSchema, FormContextType, } from '@rjsf/utils' import { getSubmitButtonOptions, getInputProps, } from '@rjsf/utils' // ── Visibility condition ──────────────────────────────────────────── // A field's uiSchema can declare: // { "ui:visible": { "field": "otherField", "equals": "someValue" } } // When the condition is not met the field is hidden entirely. interface VisibleCondition { field: string equals: unknown } function isVisible( uiSchema: Record | undefined, formData: Record | undefined, ): boolean { if (!uiSchema) return true const cond = uiSchema['ui:visible'] as VisibleCondition | undefined if (!cond) return true if (!formData) return false return formData[cond.field] === cond.equals } // ── BaseInputTemplate ─────────────────────────────────────────────── export function BaseInputTemplate< T = unknown, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = Record, >(props: BaseInputTemplateProps) { const { id, type, value, readonly, disabled, autofocus, onChange, onBlur, onFocus, schema, options, } = props const { type: inputType, ...restInputProps } = getInputProps(schema, type, options) return ( onChange(e.target.value === '' ? options.emptyValue : e.target.value)} onBlur={(e) => onBlur(id, e.target.value)} onFocus={(e) => onFocus(id, e.target.value)} type={inputType ?? type} {...restInputProps} /> ) } // ── FieldTemplate ─────────────────────────────────────────────────── export function FieldTemplate< T = unknown, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = Record, >(props: FieldTemplateProps) { const { id, label, required, children, errors, help, description, hidden, uiSchema, formContext, } = props // Check ui:visible condition const ctx = formContext as { formData?: Record } | undefined if ( hidden || !isVisible(uiSchema as Record | undefined, ctx?.formData) ) { return null } return (
{label && id !== 'root' && ( )} {description && (

{description}

)} {children} {errors} {help}
) } // ── ObjectFieldTemplate ───────────────────────────────────────────── export function ObjectFieldTemplate< T = unknown, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = Record, >(props: ObjectFieldTemplateProps) { const { title, description, properties } = props return (
{title && (

{title}

)} {description && (

{description}

)} {properties.map((prop) => prop.content)}
) } // ── ErrorList ──────────────────────────────────────────────────────── export function ErrorList< T = unknown, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = Record, >(props: ErrorListProps) { const { errors } = props if (!errors || errors.length === 0) return null return (
    {errors.map((err, i) => (
  • {err.stack}
  • ))}
) } // ── SubmitButton ───────────────────────────────────────────────────── export function SubmitButton< T = unknown, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = Record, >(props: SubmitButtonProps) { const { uiSchema } = props const { submitText, norender } = getSubmitButtonOptions(uiSchema) if (norender) return null return (
) } // ── Assembled templates export ────────────────────────────────────── export const vibeTemplates = { BaseInputTemplate, FieldTemplate, ObjectFieldTemplate, ButtonTemplates: { SubmitButton }, ErrorListTemplate: ErrorList, }