npm package: @servlyadmin/runtime-react
Description: React wrapper for Servly runtime renderer
Author: Servly
Latest version: 0.1.41

# @servlyadmin/runtime-react

React wrapper for Servly runtime renderer. Render Servly components in your React applications with full support for props, slots, and event handling.

## Installation

```bash
npm install @servlyadmin/runtime-react @servlyadmin/runtime-core
# or
yarn add @servlyadmin/runtime-react @servlyadmin/runtime-core
# or
pnpm add @servlyadmin/runtime-react @servlyadmin/runtime-core
```

## Quick Start

```tsx
import { ServlyComponent } from '@servlyadmin/runtime-react';

function App() {
  return (
    <ServlyComponent
      id="my-component"
      version="latest"
      props={{ title: 'Hello World' }}
    />
  );
}
```

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `id` | `string` | required | Component ID from the registry |
| `version` | `string` | `'latest'` | Version specifier |
| `props` | `object` | `{}` | Props to pass to the component |
| `slots` | `Record<string, ReactNode>` | - | Slot content |
| `fallback` | `ReactNode` | - | Loading/error fallback |
| `onError` | `(error: Error) => void` | - | Error callback |
| `onLoad` | `() => void` | - | Load complete callback |
| `className` | `string` | - | Wrapper class name |
| `style` | `CSSProperties` | - | Wrapper styles |
| `showSkeleton` | `boolean` | `true` | Show loading skeleton |
| `cacheStrategy` | `CacheStrategy` | `'memory'` | Cache strategy |
| `eventHandlers` | `object` | - | Event handlers by element ID |
| `children` | `ReactNode` | - | Default slot content |

## Usage Examples

### Basic Usage

```tsx
import { ServlyComponent } from '@servlyadmin/runtime-react';

function MyPage() {
  return (
    <ServlyComponent
      id="hero-section"
      props={{
        title: 'Welcome',
        subtitle: 'Get started today',
      }}
    />
  );
}
```

### With Slots

```tsx
function CardExample() {
  return (
    <ServlyComponent
      id="card-component"
      slots={{
        header: <h2>Card Title</h2>,
        footer: <button>Learn More</button>,
      }}
    >
      {/* Children go to default slot */}
      <p>This is the card content.</p>
    </ServlyComponent>
  );
}
```

### With Event Handlers

```tsx
function InteractiveExample() {
  const [count, setCount] = useState(0);

  return (
    <ServlyComponent
      id="counter-component"
      props={{ count }}
      eventHandlers={{
        'increment-btn': {
          click: () => setCount(c => c + 1),
        },
        'decrement-btn': {
          click: () => setCount(c => c - 1),
        },
      }}
    />
  );
}
```

### Loading States

```tsx
function WithLoadingState() {
  return (
    <ServlyComponent
      id="data-component"
      fallback={<div>Loading...</div>}
      onLoad={() => console.log('Component loaded!')}
      onError={(error) => console.error('Failed to load:', error)}
    />
  );
}
```

### Custom Loading Skeleton

```tsx
function WithCustomSkeleton() {
  return (
    <ServlyComponent
      id="profile-card"
      showSkeleton={false}
      fallback={
        <div className="animate-pulse">
          <div className="h-32 bg-gray-200 rounded" />
          <div className="h-4 bg-gray-200 rounded mt-4 w-3/4" />
        </div>
      }
    />
  );
}
```

### Version Pinning

```tsx
function VersionedComponent() {
  return (
    <>
      {/* Exact version */}
      <ServlyComponent id="my-component" version="1.2.3" />
      
      {/* Version range */}
      <ServlyComponent id="my-component" version="^1.0.0" />
      
      {/* Latest */}
      <ServlyComponent id="my-component" version="latest" />
    </>
  );
}
```

### Cache Control

```tsx
function CacheExample() {
  return (
    <>
      {/* Memory cache (default) */}
      <ServlyComponent id="comp1" cacheStrategy="memory" />
      
      {/* Persist to localStorage */}
      <ServlyComponent id="comp2" cacheStrategy="localStorage" />
      
      {/* No caching */}
      <ServlyComponent id="comp3" cacheStrategy="none" />
    </>
  );
}
```

### Dynamic Props

```tsx
function DynamicPropsExample() {
  const [theme, setTheme] = useState('light');
  const [user, setUser] = useState({ name: 'Guest' });

  return (
    <ServlyComponent
      id="themed-component"
      props={{
        theme,
        userName: user.name,
        timestamp: Date.now(),
      }}
    />
  );
}
```

### Error Boundary Integration

```tsx
import { ErrorBoundary } from 'react-error-boundary';

function SafeComponent() {
  return (
    <ErrorBoundary fallback={<div>Something went wrong</div>}>
      <ServlyComponent
        id="risky-component"
        onError={(error) => {
          // Log to error tracking service
          logError(error);
        }}
      />
    </ErrorBoundary>
  );
}
```

## TypeScript

Full TypeScript support:

```tsx
import { ServlyComponent, type ServlyComponentProps } from '@servlyadmin/runtime-react';

interface MyComponentProps {
  title: string;
  count: number;
}

function TypedExample() {
  return (
    <ServlyComponent<MyComponentProps>
      id="typed-component"
      props={{
        title: 'Hello',
        count: 42,
      }}
    />
  );
}
```

## Server-Side Rendering

The component handles SSR gracefully by rendering the fallback on the server and hydrating on the client.

```tsx
// Works with Next.js, Remix, etc.
function SSRPage() {
  return (
    <ServlyComponent
      id="ssr-component"
      fallback={<div>Loading component...</div>}
    />
  );
}
```

## Performance Tips

1. **Use version pinning** in production to leverage caching
2. **Prefetch components** that will be needed soon
3. **Use `cacheStrategy="localStorage"`** for components that rarely change
4. **Memoize event handlers** to prevent unnecessary re-renders

```tsx
import { useMemo, useCallback } from 'react';

function OptimizedExample() {
  const eventHandlers = useMemo(() => ({
    'btn': {
      click: () => console.log('clicked'),
    },
  }), []);

  return (
    <ServlyComponent
      id="optimized"
      eventHandlers={eventHandlers}
    />
  );
}
```

## License

MIT