npm package: @ffsm/factory
Description: A powerful component factory for React that simplifies creation of reusable components with built-in support for composition patterns, conditional rendering, prop management, and TypeScript integration.
Author: S3Tech
Latest version: 0.0.2

# @ffsm/factory

`@ffsm/factory` is a powerful component factory for React that simplifies the creation of reusable components with built-in support for composition patterns, conditional rendering, and prop management.

> _Note: Additional examples and illustrations will be added in upcoming updates._

## Table of Contents

- [Introduction](#introduction)
- [Installation](#installation)
- [Core Features](#core-features)
- [Basic Usage](#basic-usage)
- [Component Factory](#component-factory)
  - [Dynamic Props Initialization](#dynamic-props-initialization)
  - [Advanced Configuration Options](#advanced-configuration-options)
- [Compositor Integration](#compositor-integration)
  - [Installation](#compositor-installation)
  - [Usage](#compositor-usage)
  - [Slot-Based Composition](#slot-based-composition)
  - [Conditional Rendering](#conditional-rendering)
  - [Empty State Handling](#empty-state-handling)
  - [Combined Features](#combined-features)
- [Integration with Tailwind CSS](#integration-with-tailwind-css)
  - [Creating Tailwind Component Libraries](#creating-tailwind-component-libraries)
  - [Building UI Systems with Tailwind + Factory](#building-ui-systems-with-tailwind--factory)
  - [Advantages Over Direct Tailwind Usage](#advantages-over-direct-tailwind-usage)
- [API Reference](#api-reference)
  - [factory()](#factory)
  - [Init Props](#init-props)
  - [Options](#options)
- [Type System](#type-system)
  - [Core Types](#core-types)
  - [Using Generic Types](#using-generic-types)
  - [Advanced Type Features](#advanced-type-features)
- [Utilities](#utilities)
  - [clsx](#clsx)
- [Frequently Asked Questions](#frequently-asked-questions)
- [Why Choose @ffsm/factory?](#why-choose-ffsmfactory)
  - [Compared to UI Libraries](#compared-to-ui-libraries)
  - [Compared to Styling Libraries](#compared-to-styling-libraries)
  - [Compared to Component Utilities](#compared-to-component-utilities)
- [Performance Considerations](#performance-considerations)
- [Compatibility](#compatibility)
- [Related Packages](#related-packages)

## Introduction

`@ffsm/factory` is a powerful component creation system for React that streamlines how you build, compose,
and manage reusable UI components. Unlike traditional component libraries, factory doesn't impose design opinions
but instead focuses on providing a flexible and type-safe foundation for creating your own component ecosystem.

At its core, `@ffsm/factory` solves common challenges in component development:

- **Component Creation Overhead**: Simplifies creating consistent components with less boilerplate
- **Prop Management Complexity**: Handles prop forwarding, filtering, and merging automatically
- **Type Safety Challenges**: Provides comprehensive TypeScript support with proper generic typing
- **Composition Patterns**: Offers built-in patterns for component composition
- **UI Pattern Repetition**: Consolidates common UI patterns into declarative APIs

The library comes in two versions:

- **Basic Factory** (`@ffsm/factory`): Core functionality for component creation, styling, and prop management
- **Compositor Factory** (`@ffsm/factory/compositor`): Extended version with advanced UI patterns like conditional rendering, slots, and empty states

## Installation

Installing `@ffsm/factory` is straightforward with your preferred package manager:

```bash
# Using npm
npm install @ffsm/factory

# Using yarn
yarn add @ffsm/factory

# Using pnpm
pnpm add @ffsm/factory
```

Basic vs. Compositor Installation

`@ffsm/factory` comes in two versions:

1. **Basic Factory**: The core package with essential component creation features

```jsx
import { factory } from '@ffsm/factory';
```

2. **Compositor-Enabled Factory**: Extended version with advanced UI patterns

```bash
# Install both packages for compositor features
npm install @ffsm/factory @ffsm/compositor
```

```jsx
import { factory } from '@ffsm/factory/compositor';
```

**TypeScript Support**

`@ffsm/factory` includes built-in TypeScript types - no additional packages required.

**Peer Dependencies**

- React 16.8+ (for Hooks support)
- React DOM 16.8+

**Optional Integrations**

- **Tailwind CSS**: Works excellently with Tailwind for utility-first styling
- **CSS Modules**: Fully compatible with CSS Modules and other styling approaches
- **Other UI Libraries**: Can wrap components from any React UI library

Choose the installation that matches your requirements - start with the basic package for simple component creation,
or include the compositor package for advanced UI patterns.

## Core Features

`@ffsm/factory` provides a comprehensive set of features to streamline React component development:

- **Component Creation**: Easily create reusable components with consistent APIs
- **Prop Management**: Smart prop merging and filtering with type safety
- **Ref Forwarding**: Automatic ref handling for all created components
- **TypeScript Integration**: Full TypeScript support with proper generic types
- **Flexible API**: Support for static and dynamic initialization
- **Template Functions**: Customize component rendering with template functions
- **Composition Patterns**: Built-in support for advanced UI patterns (with compositor)

### Basic Factory Features

The core factory functionality focuses on simplified component creation:

```tsx
import { factory } from '@ffsm/factory';

// Create a simple button component
const Button = factory<{}>('Button', {
  className: 'btn',
  as: 'button',
});

// Use it in your app
function App() {
  return (
    <Button className="btn-primary" onClick={handleClick}>
      Click Me
    </Button>
  );
}
```

### Compositor Integration Features

When used with the compositor package, additional UI patterns are available:

- **Conditional Rendering**: Show components based on conditions or state
- **Empty State Handling**: Display fallback content when children are empty
- **Slot-Based Composition**: Render children into specific locations in a component
- **Node-Based Rendering**: Conditionally render based on children existence

```tsx
import { factory } from '@ffsm/factory/compositor';

// Component that only renders for authenticated users
const ProtectedContent = factory<{}>('ProtectedContent', {
  condition: (props) => props.isAuthenticated,
  conditionFallback: <LoginPrompt />,
});

// Usage
<ProtectedContent isAuthenticated={user?.authenticated}>
  <UserDashboard />
</ProtectedContent>;
```

### Advanced Prop Management

Factory components automatically handle:

- **Prop Forwarding**: Pass appropriate props to the DOM or wrapped components
- **Prop Merging**: Intelligently combine className, style and other props
- **Prop Filtering**: Exclude specific props from being forwarded to DOM elements
- **Custom Prop Logic**: Control exactly which props get forwarded and how

All these features are designed to work together seamlessly, providing a robust foundation
for building React component libraries or design systems.

## Basic Usage

Getting started with `@ffsm/factory` is simple and straightforward. The library provides an intuitive API
for creating reusable React components with minimal boilerplate:

```tsx
import { factory } from '@ffsm/factory';

// Create a simple button component
const Button = factory<{}>('Button', {
  className: 'btn',
  as: 'button',
});

// Use it in your application
function App() {
  return (
    <Button className="btn-primary" onClick={() => alert('Clicked!')}>
      Click Me
    </Button>
  );
}
```

### Creating Components

The `factory()` function takes three parameters:

- **Display Name**: Used in React DevTools for easier debugging
- **Initial Props** _(optional)_: Static props or a function returning props
- **Options** _(optional)_: Additional configuration for the component

```tsx
// Static props initialization
const Card = factory<{}>('Card', {
  className: 'card',
  as: 'div',
});

// Dynamic props based on component props
const Button = factory<{ variant?: 'primary' | 'secondary' }>(
  'Button',
  (props) => ({
    className: `btn ${props.variant ? `btn-${props.variant}` : ''}`,
    as: 'button',
  })
);
```

### Using Factory Components

Factory components behave like standard React components:

```jsx
// Props are merged with initial props
<Button className="mt-4" onClick={handleClick}>
  Submit
</Button>;

// Props can be spread
const buttonProps = { className: 'large', disabled: true };
<Button {...buttonProps}>Cancel</Button>;

// Ref forwarding works automatically
const buttonRef = useRef < HTMLButtonElement > null;
<Button ref={buttonRef}>Focus Me</Button>;
```

### Customizing Element Type

You can specify the element type using the `as` prop:

```tsx
// Create a component with default element type
const Text = factory<{}>('Text', {
  className: 'text',
});

// Override element type when using the component
<Text as="h1" className="text-xl">Heading</Text>
<Text as="p" className="text-sm">Paragraph</Text>
<Text as="span" className="text-xs">Small text</Text>
```

### Type Safety

Factory components are fully typed with TypeScript, providing excellent autocomplete and type checking:

```tsx
// Define component-specific props
type ButtonProps = {
  variant?: 'primary' | 'secondary' | 'outline';
  size?: 'sm' | 'md' | 'lg';
};

// Create type-safe component
const Button = factory<ButtonProps>('Button', (props) => ({
  className: `btn btn-${props.variant || 'primary'} btn-${props.size || 'md'}`,
  as: 'button',
}));

// Type checking and autocomplete work as expected
<Button
  variant="primary" // ✓ Autocomplete for 'primary', 'secondary', 'outline'
  size="lg" // ✓ Autocomplete for 'sm', 'md', 'lg'
  onClick={() => {}} // ✓ Standard button props available
/>;
```

These examples demonstrate the foundation of using `@ffsm/factory` for component creation.
The subsequent sections will explore more advanced patterns and features.

## Component Factory

The component factory is the heart of `@ffsm/factory`, providing a flexible and type-safe way to
create reusable React components. This section explores its capabilities, from basic usage to advanced
configuration options.

**Creating Components with Factory**

The `factory()` function streamlines the process of creating React components by handling boilerplate
code and providing a consistent API:

```tsx
import { factory } from '@ffsm/factory';

// Create a simple button component
const Button = factory<{}>('Button', {
  className: 'btn',
  as: 'button',
});

// Create a card component
const Card = factory<{}>('Card', {
  className: 'card',
});
```

When you create a component with `factory()`, it:

1. Creates a forward-ref component with the specified display name
2. Handles prop merging (className, style, etc.)
3. Sets up proper type definitions with TypeScript
4. Automatically forwards refs to the underlying DOM element

### Dynamic Props Initialization

One of the most powerful features of the factory is dynamic prop initialization, which allows you to
define props based on the component's runtime props:

```tsx
import { factory } from '@ffsm/factory';

// Button component with variant support
const Button = factory<{
  variant?: 'primary' | 'secondary' | 'outline';
  size?: 'sm' | 'md' | 'lg';
}>('Button', (props) => ({
  className: `
    btn 
    ${props.variant ? `btn-${props.variant}` : 'btn-primary'} 
    ${props.size ? `btn-${props.size}` : 'btn-md'}
  `,
  as: 'button',
}));

// Usage
<Button variant="secondary" size="lg">
  Large Secondary Button
</Button>;
```

This approach enables:

- **Prop-driven styling**: Change component appearance based on props
- **Conditional attributes**: Add or remove attributes based on prop values
- **Computed props**: Derive props from multiple input props

### Advanced Configuration Options

The third parameter to `factory()` lets you configure how the component handles props:

```tsx
import { factory } from '@ffsm/factory';

// Create a link component with external link handling
const Link = factory<{
  isExternal?: boolean;
}>(
  'Link',
  {
    as: 'a',
    className: 'link',
  },
  {
    // Don't forward custom props to the DOM
    excludeProps: ['isExternal'],

    // Custom template function to add security attributes to external links
    template: (Component, props, initProps) => (
      <Component
        {...props}
        target={initProps.isExternal ? '_blank' : undefined}
        rel={initProps.isExternal ? 'noopener noreferrer' : undefined}
      />
    ),
  }
);

// Usage
<Link href="https://example.com" isExternal>
  External Link
</Link>;
```

**Available Options**

The factory accepts several configuration options to customize behavior:

- **excludeProps**: Array of prop names that shouldn't be forwarded to DOM
- **shouldForwardProp**: Function to determine if a prop should be forwarded
- **template**: Custom rendering template for more complex component structures

**Custom Templates**

The template option gives you complete control over how your component renders:

```tsx
// Create a form field with label and error handling
const FormField = factory<{
  label?: string;
  error?: string;
}>(
  'FormField',
  {
    as: 'input',
    className: 'form-control',
  },
  {
    excludeProps: ['label', 'error'],
    template: (Component, props, initProps) => (
      <div className="form-group">
        {initProps.label && (
          <label className="form-label">{initProps.label}</label>
        )}
        <Component {...props} />
        {initProps.error && <div className="form-error">{initProps.error}</div>}
      </div>
    ),
  }
);

// Usage
<FormField
  label="Email Address"
  type="email"
  placeholder="your@email.com"
  error={errors.email}
/>;
```

Templates are useful for:

- Creating layout structures around components
- Adding decorative elements based on props
- Implementing complex interaction patterns
- Creating compound components with multiple parts

By leveraging the configuration options, you can create highly customized and reusable components
while maintaining clean, developer-friendly APIs.

## Compositor Integration

The Compositor integration extends `@ffsm/factory` with advanced UI patterns leveraging
the `@ffsm/compositor` package. This powerful combination allows you to create components
with built-in support for conditional rendering, slot-based composition, and empty state handling.

### Installation

To use the compositor features, you need to install both packages:

```bash
# Using npm
npm install @ffsm/factory @ffsm/compositor

# Using yarn
yarn add @ffsm/factory @ffsm/compositor

# Using pnpm
pnpm add @ffsm/factory @ffsm/compositor
```

### Usage

Import factory from the compositor subpath to access all the enhanced features:

```tsx
// Import the compositor-enabled factory
import { factory } from '@ffsm/factory/compositor';

// Create components with advanced composition patterns
const Card = factory<{}>('Card', {
  className: 'card',
  emptyFallback: <p>No content available</p>,
});
```

### Slot-Based Composition

The slot-based composition pattern allows you to render children into designated "slots" within your component,
similar to how web components handle content projection:

```tsx
import { factory } from '@ffsm/factory/compositor';

// Create a dialog with header and content slots
const Dialog = factory<{}>('Dialog', {
  className: 'dialog',
  asSlot: true,
  children: ({ children }) => (
    <div className="dialog-container">
      <div className="dialog-header"></div>
      <div className="dialog-content">{children}</div>
    </div>
  ),
});

// Usage with content projected into the slot
<Dialog>This content will be rendered inside the dialog-content div</Dialog>;
```

### Conditional Rendering

Conditional rendering lets you show or hide components based on specific conditions:

```tsx
import { factory } from '@ffsm/factory/compositor';

// Component that only renders for authenticated users
const ProtectedContent = factory<{
  isAuthenticated: boolean;
}>('ProtectedContent', (props) => ({
  condition: props.isAuthenticated,
  conditionFallback: <LoginPrompt />,
}));

// Component with async conditions (e.g., permission check)
const AdminPanel = factory<{
  userId: string;
}>('AdminPanel', (props) => ({
  // Can return a Promise for async checks
  condition: async () => {
    const permissions = await fetchUserPermissions(props.userId);
    return permissions.includes('admin');
  },
  conditionFallback: <AccessDenied />,
}));

// Usage
<ProtectedContent isAuthenticated={Boolean(user)}>
  <UserDashboard />
</ProtectedContent>;
```

### Empty State Handling

Empty state handling provides fallback content when children are empty or non-existent:

```tsx
import { factory } from '@ffsm/factory/compositor';

// List with empty state
const UserList = factory<{}>('UserList', {
  as: 'ul',
  className: 'user-list',
  emptyFallback: <p className="empty-message">No users found</p>,
});

// Usage with conditional content
<UserList>
  {users.length > 0
    ? users.map((user) => <li key={user.id}>{user.name}</li>)
    : null}
</UserList>;
```

You can also use the `asNode` option to only render a component when it has children:

```tsx
import { factory } from '@ffsm/factory/compositor';

// Section that only renders when it has content
const Section = factory<{}>('Section', {
  className: 'section',
  asNode: true,
});

// Won't render anything
<Section />

// Will render normally
<Section>
  <h2>Section Title</h2>
  <p>Content here</p>
</Section>
```

### Combined Features

The real power of compositor integration comes from combining these patterns:

```tsx
import { factory } from '@ffsm/factory/compositor';

// Data panel component with loading, empty, and error states
const DataPanel = factory<{
  isLoading: boolean;
  error?: string;
}>('DataPanel', (props) => ({
  // Only render when not loading
  condition: !props.isLoading,
  conditionFallback: <LoadingSpinner />,

  // Show error message when there's an error
  asSlot: Boolean(props.error),
  children: props.error ? (
    <div className="error-container">{props.error}</div>
  ) : undefined,

  // When no error but no content, show empty state
  emptyFallback: <EmptyState message="No data available" />,
}));

// Usage in a data-fetching scenario
<DataPanel isLoading={loading} error={error}>
  {data &&
    data.items.map((item) => (
      <div key={item.id} className="data-item">
        {item.name}
      </div>
    ))}
</DataPanel>;
```

The compositor integration eliminates the need for repetitive conditional rendering patterns,
empty state checks, and nested component structures, resulting in cleaner and more maintainable code.

By leveraging these patterns, you can create sophisticated UI components with minimal code
while maintaining a clean, declarative API that's easy for other developers to use.

## Integration with Tailwind CSS

`@ffsm/factory` works exceptionally well with Tailwind CSS, allowing you to create reusable
components with consistent styling while maintaining the utility-first approach.

### Creating Tailwind Component Libraries

Using factory with Tailwind CSS gives you the best of both worlds: the simplicity of Tailwind's utility
classes and the reusability of component abstractions:

```tsx
import { factory, clsx } from '@ffsm/factory';

// Create a reusable button component with Tailwind classes
export const Button = factory<{
  variant?: 'primary' | 'secondary' | 'outline';
  size?: 'sm' | 'md' | 'lg';
}>('Button', (props) => ({
  as: 'button',
  className: clsx(
    // Base styles
    'font-medium rounded transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2',

    // Size variations
    props.size === 'sm' && 'px-3 py-1.5 text-sm',
    props.size === 'lg' && 'px-5 py-2.5 text-lg',
    (!props.size || props.size === 'md') && 'px-4 py-2 text-base',

    // Variant styles
    props.variant === 'primary' &&
      'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
    props.variant === 'secondary' &&
      'bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500',
    props.variant === 'outline' &&
      'border border-gray-300 text-gray-700 hover:bg-gray-50 focus:ring-gray-500',
    (!props.variant || props.variant === 'primary') &&
      'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'
  ),
}));

// Usage
<Button variant="secondary" size="lg" onClick={handleClick}>
  Save Changes
</Button>;
```

### Building UI Systems with Tailwind + Factory

You can create complete UI systems by composing factory components with Tailwind classes:

```tsx
// Card components
export const Card = factory<{}>('Card', {
  className: 'bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden',
});

export const CardHeader = factory<{}>('CardHeader', {
  className: 'px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700',
});

export const CardBody = factory<{}>('CardBody', {
  className: 'px-4 py-5 sm:p-6',
});

export const CardFooter = factory<{}>('CardFooter', {
  className: 'px-4 py-4 sm:px-6 border-t border-gray-200 dark:border-gray-700',
});

// Form components
export const FormGroup = factory<{}>('FormGroup', {
  className: 'mb-4',
});

export const Label = factory<{ required?: boolean }>('Label', (props) => ({
  as: 'label',
  className: 'block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1',
  children: props.children,
}));

export const Input = factory<{
  error?: boolean;
}>('Input', (props) => ({
  as: 'input',
  className: clsx(
    'block w-full rounded-md shadow-sm sm:text-sm',
    props.error
      ? 'border-red-300 text-red-900 placeholder-red-300 focus:border-red-500 focus:ring-red-500'
      : 'border-gray-300 focus:border-blue-500 focus:ring-blue-500'
  ),
}));
```

### Advantages Over Direct Tailwind Usage

Using factory with Tailwind provides several advantages:

- **Consistency**: Define variants and styles in one place to ensure consistent UI
- **DRY Principle**: Avoid repeating the same lengthy class strings throughout your application
- **Maintainability**: Update styling in one place rather than hunting through your codebase
- **Type Safety**: Get full TypeScript support for component variations
- **Prop-Based Styling**: Toggle styles based on props rather than conditional class composition
- **Semantic Markup**: Create semantically meaningful components instead of div-soup with classes

**With Tailwind Plugins**

Factory components work seamlessly with Tailwind plugins like `@tailwindcss/forms`:

```tsx
export const Select = factory<{
  error?: boolean;
}>('Select', (props) => ({
  as: 'select',
  className: clsx(
    'block w-full rounded-md shadow-sm sm:text-sm',
    props.error
      ? 'border-red-300 text-red-900 focus:border-red-500 focus:ring-red-500'
      : 'border-gray-300 focus:border-blue-500 focus:ring-blue-500'
  ),
}));
```

**Advanced Tailwind Integration**

For more complex scenarios, you can leverage dynamic props with Tailwind:

```tsx
import { factory, clsx } from '@ffsm/factory';

// Text component with color, size and weight variants
export const Text = factory<{
  color?: 'primary' | 'secondary' | 'error' | 'success';
  size?: 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl';
  weight?: 'normal' | 'medium' | 'semibold' | 'bold';
}>('Text', (props) => ({
  className: clsx(
    // Size mapping
    props.size === 'xs' && 'text-xs',
    props.size === 'sm' && 'text-sm',
    props.size === 'base' && 'text-base',
    props.size === 'lg' && 'text-lg',
    props.size === 'xl' && 'text-xl',
    props.size === '2xl' && 'text-2xl',
    (!props.size || props.size === 'base') && 'text-base',

    // Weight mapping
    props.weight === 'normal' && 'font-normal',
    props.weight === 'medium' && 'font-medium',
    props.weight === 'semibold' && 'font-semibold',
    props.weight === 'bold' && 'font-bold',
    (!props.weight || props.weight === 'normal') && 'font-normal',

    // Color mapping
    props.color === 'primary' && 'text-blue-600 dark:text-blue-400',
    props.color === 'secondary' && 'text-gray-600 dark:text-gray-400',
    props.color === 'error' && 'text-red-600 dark:text-red-400',
    props.color === 'success' && 'text-green-600 dark:text-green-400',
    (!props.color || props.color === 'primary') &&
      'text-gray-900 dark:text-white'
  ),
}));

// Usage
<Text size="lg" color="error" weight="bold">
  Something went wrong!
</Text>;
```

This approach gives you all the benefits of Tailwind's utility-first approach while providing
the abstraction and reusability of a component library.

## API Reference

### factory()

The core factory function for creating components with standardized patterns and prop handling.

```tsx
// Basic factory
function factory<
  AdditionalProps extends Record<string, any>,
  Element extends ElementType = 'div',
>(
  displayName: string,
  init?: InitialProps<Element, AdditionalProps>,
  options?: FactoryOptions<Element, AdditionalProps>
): ForwardRefExoticComponent<
  PropsWithoutRef<FactoryProps<Element, AdditionalProps>> &
    RefAttributes<Element>
>;

// Compositor-enabled factory
// From '@ffsm/factory/compositor'
function factory<
  AdditionalProps extends Record<string, any>,
  Element extends ElementType = 'div',
>(
  displayName: string,
  init?: InitialProps<Element, AdditionalProps>,
  options?: CompositorFactoryOptions<Element, AdditionalProps>
): ForwardRefExoticComponent<
  PropsWithoutRef<FactoryProps<Element, AdditionalProps>> &
    RefAttributes<Element>
>;
```

**Parameters**

- `displayName` (string): The display name for the component in React DevTools
- `init` _(optional)_: Initial props or function that returns props based on component props
- `options` _(optional)_: Configuration options for the factory component

**Returns**

A forward ref React component with the specified props and features.

### Init Props

The second parameter (init) of the factory function can be either an object or a function that returns an object. It accepts the following properties:

| Prop        | Type                                        | Description                                         |
| ----------- | ------------------------------------------- | --------------------------------------------------- |
| `as`        | `ElementType`                               | The base element type to render (div, button, etc.) |
| `className` | `string`, `(props) => string`               | Static or dynamic class name                        |
| `style`     | `CSSProperties`, `(props) => CSSProperties` | Static or dynamic styles                            |
| `children`  | `ReactNode`, `(props) => ReactNode`         | Static content or render function                   |
| `...props`  | `any`                                       | Any additional props to pass to the component       |

**Usage Examples**

Static initialization:

```tsx
const Card = factory<{}>('Card', {
  className: 'card p-4 rounded shadow',
  as: 'div',
});
```

Dynamic initialization:

```tsx
const Button = factory<{ variant?: 'primary' | 'secondary' }>(
  'Button',
  (props) => ({
    className: `btn ${props.variant ? `btn-${props.variant}` : 'btn-primary'}`,
    as: 'button',
  })
);
```

### Options

The third parameter (`options`) allows you to configure advanced behavior of your component:

**Basic Factory Options**

| Option              | Type                                         | Description                                                |
| ------------------- | -------------------------------------------- | ---------------------------------------------------------- |
| `excludeProps`      | `Array<string>`                              | Props to exclude from being forwarded to DOM               |
| `shouldForwardProp` | `(key: keyof Props) => boolean`              | Custom function to determine if a prop should be forwarded |
| `template`          | `(Component, props, initProps) => ReactNode` | Custom rendering template for the component                |

**Compositor Factory Options (available in '@ffsm/factory/compositor')**

| Option              | Type                             | Description                             |
| ------------------- | -------------------------------- | --------------------------------------- |
| `asSlot`            | `boolean`                        | Enable slot-based composition           |
| `asNode`            | `boolean`                        | Render only when children exist         |
| `asNodeFalsy`       | `boolean`                        | Use strict falsy checking for asNode    |
| `emptyFallback`     | `ReactNode`                      | Content to show when children are empty |
| `condition`         | `unknown` , `(props) => unknown` | Condition for conditional rendering     |
| `conditionFallback` | `ReactNode`                      | Content to show when condition is falsy |
| `conditionFalsy`    | `boolean`                        | Use strict falsy checking for condition |

**Usage Examples**

Excluding custom props:

```tsx
const Link = factory<{ isExternal?: boolean }>(
  'Link',
  {
    as: 'a',
    className: 'link',
  },
  {
    excludeProps: ['isExternal'],
  }
);
```

Custom template:

```tsx
const FormField = factory<{ label?: string; error?: string }>(
  'FormField',
  {
    as: 'input',
    className: 'form-input',
  },
  {
    excludeProps: ['label', 'error'],
    template: (Component, props, initProps) => (
      <div className="form-group">
        {initProps.label && <label>{initProps.label}</label>}
        <Component {...props} />
        {initProps.error && <div className="error">{initProps.error}</div>}
      </div>
    ),
  }
);
```

Compositor features:

```tsx
import { factory } from '@ffsm/factory/compositor';

const ProtectedContent = factory<{ isAdmin: boolean }>(
  'ProtectedContent',
  {
    className: 'protected-content',
  },
  {
    condition: (props) => props.isAdmin,
    conditionFallback: <AccessDenied />,
  }
);
```

### Types

The package exports several utility types for working with factory components:

| Type                                       | Description                                                |
| ------------------------------------------ | ---------------------------------------------------------- |
| `FactoryProps<Element, AdditionalProps>`   | Combined props type for factory components                 |
| `InitialProps<Element, AdditionalProps>`   | Type for initial props or props factory function           |
| `FactoryOptions<Element, AdditionalProps>` | Type for factory options (basic version)                   |
| `MaybeFn<Result, Props>`                   | Type that can be either a value or a function returning it |
| `ObjectProps`                              | Generic object properties type                             |

### Utilities

#### clsx

Utility for conditionally joining class names:

```tsx
import { clsx } from '@ffsm/factory';

const className = clsx(
  'base-class',
  condition && 'conditional-class',
  { 'object-key': booleanValue },
  ['array', 'of', 'classes']
);
```

## Type System

The `@ffsm/factory` package includes a comprehensive type system that provides full TypeScript support.
This section explains the key types and how to use them effectively in your components.

### Core Types

**FactoryProps<Element, AdditionalProps>**

This is the main props type for factory-created components. It combines:

- Element-specific props (like href for an anchor)
- Your custom additional props
- Common factory props (className, style, etc.)

```tsx
// Example: Creating a button with custom props
type ButtonProps = {
  variant: 'primary' | 'secondary';
  size: 'sm' | 'md' | 'lg';
};

const Button = factory<ButtonProps, 'button'>('Button', {
  className: 'btn',
  as: 'button',
});

// Usage with type checking:
<Button
  variant="primary" // ✓ Type checked
  size="sm" // ✓ Type checked
  onClick={() => {}} // ✓ Inherited from 'button' element
  invalid={true} // ✗ Type error
/>;
```

**InitialProps<Element, AdditionalProps>**

This flexible type represents initial props configuration and can be either:

1. Static object:

```tsx
const Card = factory<{}>('Card', {
  className: 'card',
  as: 'div',
});
```

2. Function that returns props based on incoming props:

```tsx
const Button = factory<ButtonProps>('Button', (props) => ({
  className: `btn btn-${props.variant} btn-${props.size}`,
  as: 'button',
}));
```

### Using Generic Types

**Custom Component Props**

Define custom props with full type safety:

```tsx
interface TabProps {
  active?: boolean;
  label: string;
  index: number;
}

const Tab = factory<TabProps>('Tab', (props) => ({
  className: props.active ? 'tab active' : 'tab',
  'aria-selected': props.active,
  role: 'tab',
  as: 'div',
}));

// Usage with TypeScript validation
<Tab
  label="Settings" // Required
  index={2} // Required
  active={true} // Optional
/>;
```

**Element Type Customization**

Specify a different base element type:

```tsx
const NavLink = factory<{}, 'a'>('NavLink', {
  className: 'nav-link',
  as: 'a',
});

// Usage with anchor-specific props
<NavLink href="/about" target="_blank">
  About
</NavLink>;
```

### Advanced Type Features

**Type Inference Best Practices**

When creating a factory component without additional props, always specify an empty object explicitly:

```tsx
// Correct approach - explicitly specify empty object
export const FormWrapper = factory<{}>('FormWrapper', {
  className: 'w-full',
});

// Not recommended - may cause type inference issues
export const FormContainer = factory('FormContainer', {
  className: 'flex w-full border border-white/20 rounded-lg',
});
```

**Conditional Props**

Create components with conditional prop requirements:

```tsx
// Better approach using union types
type DialogProps =
  | { title: string; size?: 'sm' | 'md' | 'lg'; closable: true; onClose: () => void }
  | { title: string; size?: 'sm' | 'md' | 'lg'; closable?: false; onClose?: never };

const Dialog = factory<DialogProps>('Dialog', {
  className: 'dialog',
});

// Usage:
// Valid - onClose is required when closable is true
<Dialog title="Settings" closable={true} onClose={() => setOpen(false)} />

// Valid - onClose is not allowed when closable is false
<Dialog title="Info" closable={false} />

// Invalid - missing onClose
<Dialog title="Error" closable={true} /> // TypeScript error

// Invalid - has onClose when closable is false
<Dialog title="Warning" closable={false} onClose={() => {}} /> // TypeScript error
```

**Component Composition Types**

Build complex component hierarchies with composed types:

```tsx
type CardProps = {
  title: string;
  elevated?: boolean;
};

type CardImageProps = CardProps & {
  imageSrc: string;
  imageAlt?: string;
};

const Card = factory<CardProps>('Card', {
  className: 'card',
});

const CardWithImage = factory<CardImageProps>('CardWithImage', (props) => ({
  className: `card ${props.elevated ? 'elevated' : ''}`,
  children: (
    <>
      <img src={props.imageSrc} alt={props.imageAlt || props.title} />
      <h3>{props.title}</h3>
    </>
  ),
}));
```

### Utility Types

The package exports several utility types for advanced use cases:

- `MaybeFn<Result, Props>`: Type for values that can be either direct or function-returned
- `ObjectProps`: Generic object properties type
- `FactoryProps<Element, AdditionalProps>`: Combined props for factory components
- `FactoryOptions<Element, AdditionalProps>`: Options for factory configuration

Import these types directly from the package:

```tsx
import { MaybeFn, ObjectProps, FactoryProps } from '@ffsm/factory';

// Create a type for a component that needs dynamic styling
type DynamicComponent<P = {}> = React.FC<
  P & {
    styling: MaybeFn<string, P>;
  }
>;
```

By leveraging these type utilities, you can create type-safe component APIs that provide excellent
developer experience with autocompletion and type checking.

## Utilities

`@ffsm/factory` includes several utility functions that help with common component development tasks.
These utilities can be imported directly from the package and used both within factory components
and in your application code.

### [clsx](https://npmjs.com/package/clsx)

The package includes a lightweight version of the clsx utility for conditional class name composition,
allowing you to combine class names dynamically:

```tsx
import { clsx } from '@ffsm/factory';

// Basic usage
const className = clsx(
  'base-class',
  condition && 'conditional-class',
  isActive ? 'active' : 'inactive',
  { hidden: isHidden, visible: !isHidden }
);

// Within a factory component
const Button = factory<{
  variant?: 'primary' | 'secondary';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
}>('Button', (props) => ({
  as: 'button',
  className: clsx(
    'btn',
    props.variant && `btn-${props.variant}`,
    props.size && `btn-${props.size}`,
    props.disabled && 'btn-disabled'
  ),
}));
```

The `clsx` utility supports:

- Strings: `'btn'`
- Objects: `{ 'btn-primary': isPrimary }`
- Arrays: `['btn', isActive && 'btn-active']`
- Nested conditions: `condition && [subCondition && 'class']`
- Falsy values are ignored: `false && 'hidden'` results in nothing being added

This eliminates the need for an additional package for class name management in your projects.

## Frequently Asked Questions

### How is @ffsm/factory different from styled-components?

While `styled-components` focuses on styling with CSS-in-JS, `@ffsm/factory` provides a more comprehensive
approach to component creation with built-in composition patterns, conditional rendering, and prop management.

### Can I use @ffsm/factory with other UI libraries?

Yes, @ffsm/factory works with any React-based UI library. You can wrap components from Material UI, Chakra UI,
or any other library using `factory()`.

### Does it work with React Server Components?

Yes, `@ffsm/factory` is compatible with React Server Components, but be aware that some dynamic features
might need client-side hydration.

### What's the difference between the regular factory and compositor factory?

The regular factory (`import { factory } from '@ffsm/factory'`) provides core functionality for component creation,
prop forwarding, and templates. The compositor factory (`import { factory } from '@ffsm/factory/compositor'`) adds
support for advanced UI patterns like conditional rendering, slot-based composition, and empty state handling through
integration with `@ffsm/compositor`.

### When should I use the basic factory vs. compositor factory?

Use the basic factory when you only need component creation and prop management. Use the compositor factory when
you need advanced UI patterns like conditional rendering, slots, or empty state handling. The basic factory has
fewer dependencies and a smaller bundle size.

### Does using the compositor features impact performance?

The compositor integration adds a small runtime overhead, but it's negligible for most applications. The benefits
of cleaner code and declarative patterns usually outweigh the minimal performance cost. For performance-critical
scenarios with large lists, consider memoizing components with `React.memo`.

### Do I need to install @ffsm/compositor separately?

Yes, when using the compositor features, you need to install both packages:

```bash
npm install @ffsm/factory @ffsm/compositor
```

The basic factory doesn't require the compositor package.

## Why Choose @ffsm/factory?

While there are many component libraries and styling solutions available, `@ffsm/factory` offers unique advantages
that set it apart:

### Compared to UI Libraries

Traditional UI libraries like Material UI, Chakra UI, or Ant Design provide pre-built components with specific
design systems. `@ffsm/factory` takes a different approach:

- **Zero Design Opinions**: Create components that match your exact design requirements without fighting against pre-existing styles
- **Lightweight Core**: No bloated dependencies or unused components - just the functionality you need
- **Composable Building Blocks**: Build your own design system from the ground up rather than adapting existing components
- **Progressive Adoption**: Start with a few components and gradually expand without committing to an entire UI framework

### Compared to Styling Libraries

Unlike CSS-in-JS libraries like styled-components or emotion, `@ffsm/factory`:

- **Focuses on Component Logic**: Handles not just styling but composition patterns, conditional rendering, and prop management
- **Styling Agnostic**: Works with any styling approach - CSS modules, Tailwind, utility classes, or vanilla CSS
- **Reduced Boilerplate**: Creates consistent components with fewer lines of code
- **Declarative Patterns**: Simplifies common UI patterns with prop-based APIs instead of imperative code

### Compared to Component Utilities

Headless UI libraries like Radix UI or Headless UI provide unstyled components, but `@ffsm/factory`:

- **Offers Complete Control**: Define both behavior and presentation in a unified API
- **Simplifies Implementation**: Less verbose than hook-based component creation patterns
- **Integrates Advanced Patterns**: Built-in support for slots, empty states, and conditional rendering
- **Prioritizes Developer Experience**: Consistent API with excellent TypeScript integration

### Real-World Benefits

- **Faster Development**: Create new components in minutes instead of hours
- **Consistent APIs**: Establish patterns that all team members can follow
- **Better Maintainability**: Centralized component logic with clear separation of concerns
- **Improved Type Safety**: Full TypeScript support with proper generics and inference
- **Reduced Bundle Size**: Only include the functionality you need
- **Flexible Adaptation**: Works with your existing components, libraries, and styling solutions

`@ffsm/factory` is ideal for teams building custom design systems, developers who need flexibility beyond existing UI libraries,
and projects where component consistency and maintainability are priorities.

## Performance Considerations

`@ffsm/factory` is designed with performance in mind, but there are some considerations to ensure optimal performance in your applications:

- **Component Memoization**: When rendering large lists of factory components, wrap them with React.memo to prevent unnecessary re-renders:

```tsx
const OptimizedCard = React.memo(factory<CardProps>('Card', {...}));
```

- **Bundle Size**: The core factory package is lightweight, but including the compositor features will increase bundle size.
  Use code-splitting to only load the compositor features when needed:

```tsx
// Dynamic import of compositor-enabled components
const AdminPanel = lazy(() => import('./AdminPanel'));
```

- **Conditional Rendering**: When using conditional rendering frequently, prefer the declarative compositor approach over
  imperative conditionals for better readability and maintainability.

## Compatibility

`@ffsm/factory` is designed to work across a wide range of React environments:

- **React Versions**: Compatible with React 16.8+ (requires hooks support)
- **React Frameworks**:
  - Next.js (both Pages and App Router)
  - Create React App
  - Vite
  - Remix
  - Gatsby
  - Any other React-based framework
- **TypeScript**: Full TypeScript support with proper typing and generics
- **React Server Components**: Compatible with React Server Components, though some dynamic features require client components
- **Styling Solutions**: Works with any styling approach:
  - Tailwind CSS
  - CSS Modules
  - Styled Components / Emotion
  - Plain CSS
  - CSS-in-JS libraries
- **Browsers**: Supports all modern browsers without polyfills

## Related Packages

### Core Packages

- `@ffsm/compositor`: The companion package that provides the advanced composition utilities used by factory's compositor integration. Install this package to use the advanced features like slots, conditional rendering, and empty state handling.

These packages are designed to work together to provide a complete solution for building React applications, but each can be used independently according to your specific needs.