npm package: @stvnprkns/formless-registry
Description: Semantic form schema registry for Formless - A type-safe registry for form field definitions with metadata
Author: Formless Team
Latest version: 0.1.1

# @stvnprkns/formless-registry

A type-safe, semantic form field registry for Formless applications. This package provides a centralized registry of form field definitions with rich metadata, validation rules, and type information.

## Features

- 🏷️ **Type-Safe**: Built with TypeScript for excellent developer experience
- 📝 **Rich Metadata**: Each field includes type information, validation rules, labels, and more
- 🗂️ **Categorized**: Organize fields into logical groups (Personal, Account, Address, etc.)
- 🔄 **Versioned**: Track field additions and changes
- ⚠️ **Deprecation Support**: Mark fields as deprecated while maintaining backward compatibility
- 🧪 **Tested**: Comprehensive test coverage
- 📦 **Tree-shakeable**: Only bundle what you use
- 🌐 **Universal**: Works in both Node.js and browser environments
- 📱 **Framework Agnostic**: Use with any frontend framework or vanilla JS

## Installation

```bash
# Using npm
npm install @stvnprkns/formless-registry

# Using yarn
yarn add @stvnprkns/formless-registry

# Using pnpm
pnpm add @stvnprkns/formless-registry
```

## Table of Contents

- [Quick Start](#quick-start)
- [API Reference](#api-reference)
- [Field Configuration](#field-configuration)
- [Categories](#categories)
- [TypeScript Support](#typescript-support)
- [Examples](#examples)
- [Contributing](#contributing)
- [License](#license)

## Quick Start

### Basic Usage

```typescript
import { formlessRegistry } from '@stvnprkns/formless-registry';

// Access field definitions
const emailField = formlessRegistry.fields.email;
console.log('Email Field:', {
  label: emailField.label,
  type: emailField.type,
  required: emailField.required,
  pattern: emailField.pattern
});

// Check registry version
console.log('Registry Version:', formlessRegistry.version);

// List all available fields
console.log('Available Fields:', Object.keys(formlessRegistry.fields));
```

### Accessing Fields by Category

```typescript
// Get all personal information fields
const personalFields = Object.entries(formlessRegistry.fields)
  .filter(([_, field]) => field.category === 'personal')
  .map(([key, field]) => ({
    key,
    label: field.label,
    type: field.type
  }));

console.log('Personal Information Fields:', personalFields);
```

## API Reference

### `formlessRegistry`

The main registry object that contains all field definitions and metadata.

#### Properties

```typescript
// Current version of the registry
version: string;

// Object containing all field definitions
fields: Record<string, FieldConfig>;

// Object containing category metadata (if any)
categories?: Record<string, CategoryConfig>;

// Additional metadata about the registry
meta?: {
  name?: string;
  description?: string;
  [key: string]: any;
};
```

### `FieldConfig`

Interface representing a field configuration:

```typescript
interface FieldConfig {
  // The type of the field (e.g., 'text', 'email', 'select')
  type: FieldType;
  
  // Human-readable label for the field
  label: string;
  
  // Description or help text
  description?: string;
  
  // Whether the field is required
  required?: boolean;
  
  // Validation pattern (regex string)
  pattern?: string;
  
  // Error message when pattern validation fails
  patternMessage?: string;
  
  // Category for grouping related fields
  category?: string;
  
  // Whether the field is deprecated
  deprecated?: boolean;
  
  // Version when this field was added
  version?: string;
  
  // Example values for the field
  examples?: any[];
  
  // Additional field-specific options
  [key: string]: any;
}
```

### `CategoryConfig`

```typescript
interface CategoryConfig {
  // Display name for the category
  label: string;
  
  // Optional description
  description?: string;
  
  // Additional metadata
  [key: string]: any;
}
```

## Field Configuration

Each field in the registry is a `FieldConfig` object with properties like:

```typescript
{
  "email": {
    "type": "email",
    "label": "Email Address",
    "description": "A valid email address",
    "required": true,
    "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",
    "patternMessage": "Please enter a valid email address",
    "category": "account",
    "examples": ["user@example.com"],
    "deprecated": false,
    "version": "1.0.0"
  }
}
```

## Categories

The registry organizes fields into logical categories for easier management:

- **personal**: Personal Information (name, date of birth, etc.)
- **account**: Account Information (email, username, password)
- **address**: Physical Address (street, city, zip code)
- **payment**: Payment Information (credit card, billing details)
- **preferences**: User Preferences (language, theme, notifications)
- **other**: Additional Information

## TypeScript Support

The package includes TypeScript type definitions. Import types like this:

```typescript
import type { FieldConfig, FieldType, FormlessSchema } from '@stvnprkns/formless-registry';

// Example of using types
function validateField(field: FieldConfig, value: any): boolean {
  if (field.required && !value) return false;
  if (field.pattern && value) {
    const regex = new RegExp(field.pattern);
    return regex.test(value);
  }
  return true;
}
```

## Examples

### 1. Form Generation

```typescript
function renderForm(fields: string[]) {
  return fields.map(fieldKey => {
    const field = formlessRegistry.fields[fieldKey];
    if (!field) return null;
    
    return `
      <div class="form-group">
        <label for="${fieldKey}">
          ${field.label}
          ${field.required ? '<span class="required">*</span>' : ''}
        </label>
        <input 
          type="${field.type}" 
          id="${fieldKey}" 
          name="${fieldKey}" 
          ${field.required ? 'required' : ''}
          ${field.pattern ? `pattern="${field.pattern}"` : ''}
          placeholder={field.placeholder || ''}
        />
        {field.description && (
          <div class="help-text">${field.description}</div>
        )}
      </div>
    `;
  }).join('\n');
}
```

### 2. Field Validation

```typescript
function validateForm(data: Record<string, any>) {
  const errors: Record<string, string> = {};
  
  Object.entries(data).forEach(([fieldKey, value]) => {
    const field = formlessRegistry.fields[fieldKey];
    if (!field) return;
    
    if (field.required && !value) {
      errors[fieldKey] = `${field.label} is required`;
      return;
    }
    
    if (field.pattern && value) {
      const regex = new RegExp(field.pattern);
      if (!regex.test(value)) {
        errors[fieldKey] = field.patternMessage || 'Invalid format';
      }
    }
  });
  
  return Object.keys(errors).length > 0 ? errors : null;
}
```

### 3. Dynamic Form with React

```tsx
import React from 'react';
import { formlessRegistry } from '@stvnprkns/formless-registry';

function DynamicForm() {
  const [formData, setFormData] = React.useState({});
  const [errors, setErrors] = React.useState({});

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: value
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const validationErrors = validateForm(formData);
    if (validationErrors) {
      setErrors(validationErrors);
      return;
    }
    // Submit form...
  };

  return (
    <form onSubmit={handleSubmit}>
      {Object.entries(formlessRegistry.fields).map(([key, field]) => (
        <div key={key} className="form-group">
          <label htmlFor={key}>
            {field.label}
            {field.required && <span className="required">*</span>}
          </label>
          <input
            type={field.type}
            id={key}
            name={key}
            value={formData[key] || ''}
            onChange={handleChange}
            required={field.required}
            pattern={field.pattern}
            placeholder={field.placeholder}
            className={errors[key] ? 'error' : ''}
          />
          {field.description && (
            <div className="help-text">{field.description}</div>
          )}
          {errors[key] && (
            <div className="error-message">{errors[key]}</div>
          )}
        </div>
      ))}
      <button type="submit">Submit</button>
    </form>
  );
}
```

## Contributing

Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) to get started.

## License

MIT © [Your Name]

## Changelog

### 0.1.0
- Initial release of formless-registry
- Added core field definitions
- TypeScript support
- Comprehensive documentation

```typescript
function validateField(fieldName: string, value: string): boolean {
  const field = formlessRegistry.fields[fieldName as keyof typeof formlessRegistry.fields];
  if (!field) return false;
  
  if (field.required && !value) return false;
  if (field.pattern && !new RegExp(field.pattern).test(value)) return false;
  if (field.minLength && value.length < field.minLength) return false;
  if (field.maxLength && value.length > field.maxLength) return false;
  
  return true;
}

// Example usage
validateField('email', 'test@example.com'); // true
validateField('email', 'invalid-email');    // false
```

### Getting Fields by Category

```typescript
function getFieldsByCategory(category: string) {
  return Object.entries(formlessRegistry.fields)
    .filter(([_, config]) => config.category === category)
    .map(([key, config]) => ({
      key,
      label: config.label,
      type: config.type,
      required: config.required,
    }));
}

// Get all personal information fields
const personalFields = getFieldsByCategory('personal');
```

### Getting Fields by Type

```typescript
function getFieldsByType(type: FieldType) {
  return Object.entries(formlessRegistry.fields)
    .filter(([_, config]) => config.type === type)
    .map(([key, config]) => ({
      key,
      label: config.label,
      category: config.category,
    }));
}

// Get all select fields
const selectFields = getFieldsByType('select');
```

## API Reference

### `formlessRegistry`

The main registry object containing all field definitions.

#### Properties

- `version: string` - The current version of the registry
- `fields: Record<string, FieldConfig>` - Object containing all field definitions
- `categories?: Record<string, CategoryConfig>` - Optional categories for organizing fields
- `meta?: Record<string, any>` - Additional metadata about the registry

### Types

#### `FieldConfig`

```typescript
interface FieldConfig {
  // Basic field information
  type: FieldType;
  label: string;
  description?: string;
  required?: boolean;
  
  // Validation
  pattern?: string;
  patternMessage?: string;
  minLength?: number;
  maxLength?: number;
  min?: number | string;
  max?: number | string;
  
  // Metadata
  category?: string;
  deprecated?: boolean;
  version?: string;
  examples?: any[];
  
  // For select/radio fields
  options?: Array<{
    label: string;
    value: any;
    disabled?: boolean;
  }>;
}
```

#### `FieldType`

```typescript
type FieldType =
  | 'text'
  | 'email'
  | 'password'
  | 'number'
  | 'tel'
  | 'url'
  | 'date'
  | 'time'
  | 'datetime-local'
  | 'month'
  | 'week'
  | 'color'
  | 'checkbox'
  | 'radio'
  | 'select'
  | 'textarea'
  | 'hidden';
```

## Development

### Prerequisites

- Node.js 16+
- npm or yarn

### Installation

```bash
git clone https://github.com/your-org/formless.git
cd formless/packages/registry
npm install
```

### Building

```bash
# Build the project
npm run build

# Watch for changes
npm run build -- --watch
```

### Testing

```bash
# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Generate test coverage
npm run test:coverage
```

### Linting

```bash
# Run linter
npm run lint

# Fix linting issues
npm run lint:fix
```

## Contributing

Contributions are welcome! Please read our [contributing guide](CONTRIBUTING.md) to get started.

## License

MIT © [Formless Team](https://github.com/formless-js)
    description?: string;
    [key: string]: any;
  };
}
```

## Field Configuration

Each field in the registry is a `FieldConfig` object with properties like:

```typescript
{
  type: FieldType;  // 'text', 'email', 'password', etc.
  label: string;    // Human-readable label
  description?: string;  // Help text
  required?: boolean;    // Whether the field is required
  default?: any;         // Default value
  // ... and many more
}
```

## Extending the Registry

You can extend the default registry with your own fields:

```typescript
import { formlessRegistry } from '@formless/registry';

const customRegistry = {
  ...formlessRegistry,
  fields: {
    ...formlessRegistry.fields,
    customField: {
      type: 'text',
      label: 'Custom Field',
      // ...
    }
  }
};
```

## Building

```bash
npm install
npm run build
```

## License

MIT