Skip to content

Latest commit

 

History

History
228 lines (183 loc) · 5.83 KB

File metadata and controls

228 lines (183 loc) · 5.83 KB
title Plugin Form

import { InteractiveDemo } from '@/app/components/InteractiveDemo'; import { PluginLoader } from '@/app/components/PluginLoader';

Advanced form components with validation, multi-step forms, and comprehensive field support.

Installation

npm install @object-ui/plugin-form

<PluginLoader plugins={['form']}>

Interactive Examples

Features

  • Form Builder - Create complex forms from schemas
  • Validation - Built-in validation with custom rules
  • Multi-Step Forms - Wizard-style multi-step forms
  • Field Types - All standard HTML5 input types
  • Form State - Automatic state management
  • Error Handling - Field-level and form-level errors

Schema API

Form

{
  type: 'form',
  fields: FormField[],
  submitLabel?: string,
  cancelLabel?: string,
  onSubmit?: (data) => void,
  onCancel?: () => void,
  className?: string
}

Form Field

interface FormField {
  name: string;
  type: string;                   // 'input', 'select', 'checkbox', etc.
  label: string;
  placeholder?: string;
  required?: boolean;
  validation?: ValidationRule[];
  defaultValue?: any;
  disabled?: boolean;
  className?: string;
}

Tabbed field layout (fieldTabs)

A sectioned form stays one form: declare the tabs on it and the renderer distributes the fields into panels, instead of rendering a form per section (which strands every section but the first outside the submit, and lets an inactive tab unmount along with its values).

{
  type: 'form',
  fields: [/* every tab's fields, in one flat list */],
  fieldTabs: [
    { key: 'basics', label: 'Basics', fields: ['subject', 'status'] },
    { key: 'detail', label: 'Detail', description: 'Anything else', fields: ['description'] },
  ],
  defaultFieldTab?: 'basics',       // defaults to the first tab
  fieldTabsPosition?: 'top',        // 'top' | 'bottom' | 'left' | 'right'
}
  • Panels are force-mounted and only CSS-hidden, so a tab the user leaves keeps its values and its validation.
  • A failed submit activates the tab holding the first offending field and marks every tab with a rejected field — client rules and server fields[] alike.
  • Fields no tab claims render above the tab strip rather than disappearing.
  • Needs at least two tabs; ignored when the form uses children.

ModalForm (contentLayout: 'tabbed') and TabbedForm build on this.

Split field layout (fieldPanes)

Side-by-side panels follow the same rule: the <form> wraps the whole panel group and each pane holds only fields, so one react-hook-form instance spans the divider.

{
  type: 'form',
  fields: [/* every pane's fields, in one flat list */],
  fieldPanes: [
    { key: 'primary', fields: ['subject'], defaultSize: 50 },
    { key: 'secondary', fields: ['status', 'priority'], defaultSize: 50, minSize: 20 },
  ],
  fieldPanesOrientation?: 'horizontal',   // 'horizontal' | 'vertical'
  fieldPanesResizable?: true,             // false pins the divider
}
  • A submit from anywhere carries every pane's values, and a field rule in one pane can read a field in another — neither works with a form per panel.
  • defaultSize / minSize are percentages of the group.
  • Each pane is its own @container, so a multi-column group collapses as the divider is dragged narrower.
  • Fields no pane claims render above the panel group rather than disappearing.
  • Needs at least two panes; ignored when the form uses children or fieldTabs.

SplitForm builds on this: section 1 becomes the primary pane, the rest stack in the secondary one behind inline section headers.

Usage

Auto-registration (Side-effect Import)

import '@object-ui/plugin-form';

Manual Registration

import { formComponents } from '@object-ui/plugin-form';
import { ComponentRegistry } from '@object-ui/core';

Object.entries(formComponents).forEach(([type, component]) => {
  ComponentRegistry.register(type, component);
});

Examples

Form with Validation

{
  "type": "form",
  "fields": [
    {
      "name": "username",
      "type": "input",
      "label": "Username",
      "required": true,
      "validation": [
        { "type": "minLength", "value": 3, "message": "Min 3 characters" },
        { "type": "maxLength", "value": 20, "message": "Max 20 characters" }
      ]
    },
    {
      "name": "password",
      "type": "input",
      "inputType": "password",
      "label": "Password",
      "required": true,
      "validation": [
        { "type": "minLength", "value": 8, "message": "Min 8 characters" }
      ]
    }
  ],
  "submitLabel": "Sign Up"
}

Multi-Step Form

{
  "type": "multi-step-form",
  "steps": [
    {
      "title": "Personal Info",
      "fields": [
        { "name": "firstName", "type": "input", "label": "First Name", "required": true },
        { "name": "lastName", "type": "input", "label": "Last Name", "required": true }
      ]
    },
    {
      "title": "Contact Info",
      "fields": [
        { "name": "email", "type": "input", "inputType": "email", "label": "Email", "required": true },
        { "name": "phone", "type": "input", "inputType": "tel", "label": "Phone" }
      ]
    }
  ]
}

Field Types

The plugin supports these field types:

  • input - Text, email, password, number, tel, url, etc.
  • textarea - Multi-line text input
  • select - Dropdown select
  • checkbox - Single checkbox
  • radio-group - Radio button group
  • date-picker - Date selection
  • file-upload - File upload

TypeScript Support

import type { FormSchema, FormField } from '@object-ui/plugin-form';

const loginForm: FormSchema = {
  type: 'form',
  fields: [...],
  submitLabel: 'Sign In'
};

License

MIT