Skip to content

operativeit/schema-form

Repository files navigation

Schema Form Engine

A high-performance, schema-driven form generation engine for Vue 3, designed for complex enterprise data models.

🚀 Key Features

  • High Performance: Optimized rendering engine with pre-computed schema resolution and layout bindings.
  • Advanced Data Binding:
    • JSONPath: Full support for absolute ($) and relative (@) paths.
    • Parent Traversal: Use ^ to access parent contexts (e.g., ^.prop).
  • Robust Validation:
    • Metadata-Driven: Validators are self-describing with usage metadata.
    • i18n Built-in: Native integration with vue-i18n for localized error messages and validator definitions.
    • Engine-Level Gating: Prevents submission if any field is invalid.
  • Framework Agnostic: Decoupled from any specific UI library. Bring your own Shadcn, Vuetify, or unstyled HTML components.
  • Modular Architecture:
    • SchemaForm: Root orchestrator managing state and layout.
    • SchemaRenderer: Recursive component for efficient tree rendering.
    • Registry: Dependency injection system for components and validators.
  • TypeScript First: Strict typing for schemas, validators, and engine context.

📦 Usage

The engine is framework-agnostic. You must inject your UI components (theme) via the components prop.

<template>
  <SchemaForm
    :schema="schema"
    :components="theme"
    v-model="formData"
    @submit="handleSubmit"
  />
</template>

<script setup lang="ts">
import { ref } from "vue";
import { SchemaForm } from "@operativeit/schema-form";
// Import your local theme definition (map of component names -> Vue components)
import { ShadcnTheme } from "@/components/schema-form/themes/shadcn";

const theme = ShadcnTheme;

const formData = ref({
  user: {
    name: "John Doe",
    email: "",
  },
});

const schema = [
  {
    component: "Text", // Matches key in your Theme object
    model: "$.user.name",
    label: "Name",
    rules: "required|min:3",
  },
  {
    component: "Text",
    model: "$.user.email",
    label: "Email",
    rules: "required|email",
  },
];

const handleSubmit = () => {
  console.log("Form Submitted:", formData.value);
};
</script>

🧠 Architecture

Form Engine (useFormEngine.ts)

The core brain of the system. It handles:

  • State Management: Wraps your data model in a reactive context.
  • Path Resolution:
    • $ : Root
    • @ : Current Context
    • ^ : Parent Context (Multi-level supported, e.g., ^^.prop)
  • Query/Update: Uses optimized JSONPath lookups for reading and writing deep values.

Schema Renderer (SchemaRenderer.vue)

An optimized recursive component that:

  • Pre-computes paths and bindings to minimize re-renders.
  • Iterates over schema definitions efficiently.
  • Resolves component definitions from the registry dynamically.

Validation System

Validation is decoupled and metadata-driven.

  • Validators: Pure functions located in utils/validators.ts.
  • Metadata: Each validator exports descriptive metadata (label, options) used by the Form Builder.
  • Internationalization: Error messages and metadata use t() keys for full localization.

🛠 Advanced Features

Path Resolution Examples

Symbol Meaning Example
$ Root $.store.book[0]
@ Current @.title (inside book object)
^ Parent ^.category (sibling of parent array)
^^ Grandparent ^^.storeName

Adding Custom Validators

Validators can be added via the module system. Create a file in utils/validators/ and it will be auto-registered.

// utils/validators/myValidator.ts
export const myValidator = (value, options) => {
  return value === "correct" ? undefined : "Error!";
};

export const metadata = {
  label: "My Validator",
  description: "Checks if value is 'correct'",
};

export const extend = (registry) => {
  registry.myValidator = myValidator;
};

a a