npm package: @galaxy-dev/metadsl-runtime
Description: MetaDSL runtime - Component-agnostic DSL renderer
Latest version: 0.10.9

# @galaxy-dev/metadsl-runtime

Component-agnostic DSL runtime for MetaDSL.

## Architecture

### Core Design Principles

1. **Unified Evaluation Context** - Scope chain system for expression evaluation
2. **Component Library Agnostic** - Adapter pattern for different UI libraries
3. **Unified Form API** - Single interface for local and global form access
4. **Reactive by Design** - Field-level subscriptions with precise re-rendering

## Key Features

- 🎨 **UI Agnostic** - Works with any UI library via adapters
- 🔗 **Evaluation Context** - Scope chain for page/form/nested contexts
- 📝 **Form Registry** - Global form access from anywhere
- ⚡ **Performance** - Field-level subscriptions, stable refs, memoization
- 🌍 **i18n** - Automatic translation
- 📱 **Responsive** - Built-in responsive hooks

## Installation

```bash
pnpm add @galaxy-dev/metadsl-runtime @galaxy-dev/metadsl-core
```

## Core Concepts

### 1. EvaluationContext - Scope Chain

Similar to JavaScript's scope chain, contexts inherit from parent:

```tsx
<DSLPageProvider context={{ user: { name: 'Alice' } }}>
  {/* Layer 1: { user: {...} } */}
  <Text content="${user.name}" /> {/* ✅ "Alice" */}
  <Form name="myForm">
    {/* Layer 2: { user: {...}, form: {...} } */}
    <Field name="email" />

    {/* Components can access form data! */}
    <Card visible="${form.email}">
      <Text content="${user.name}" /> {/* ✅ Accesses parent scope */}
    </Card>

    <Form name="nested">
      {/* Layer 3: form shadowed, user still accessible */}
      <Field name="city" />
      <Text content="${form.city}" /> {/* ✅ nested form */}
      <Text content="${user.name}" /> {/* ✅ page context */}
    </Form>
  </Form>
</DSLPageProvider>
```

### 2. Unified Form API (DSLFormApi)

Single interface for both local (Context) and global (Registry) access:

```tsx
// Inside form tree
function MyField() {
  const form = useFormContext(); // DSLFormApi
  const email = form.getValue('email');
  form.setValue('email', 'new@example.com');
  return <input value={email} />;
}

// Outside form tree
function SubmitAll() {
  const { getForm } = useFormRegistry();
  const form1 = getForm('form1'); // DSLFormApi (same interface!)
  const form2 = getForm('form2');

  await form1?.submit();
  await form2?.submit();
}
```

### 3. Expression Evaluation

All renderers use unified expression evaluator with context merging:

```tsx
// ComponentRenderer - accesses evaluation context
<Card visible="${form.isVIP && user.isPremium}">
  <Text content="${user.name}" />
</Card>

// FieldRenderer - merges context with subscribed field values
<Field
  name="total"
  value="${form.quantity * form.price}"
  disabled="${form.quantity === 0}"
/>
```

## Usage

### Basic Example

```tsx
import { DSLPageProvider } from '@galaxy-dev/metadsl-runtime';

<DSLPageProvider
  page={pageDSL}
  context={{ user: currentUser }} // Page-level context
  locale="zh-CN"
>
  {/* Your page content */}
</DSLPageProvider>;
```

### With Form Registry

```tsx
import { FormRegistryProvider } from '@galaxy-dev/metadsl-runtime';

<FormRegistryProvider debug={isDev}>
  <DSLPageProvider page={pageDSL}>
    <Form name="form1">...</Form>
    <Form name="form2">...</Form>

    {/* Access forms from anywhere */}
    <SubmitAllButton />
  </DSLPageProvider>
</FormRegistryProvider>;
```

### Using Hooks

```tsx
import {
  useFormContext,
  useFormRegistry,
  useEvaluationContext,
  useBreakpoint,
} from '@galaxy-dev/metadsl-runtime';

function CustomComponent() {
  // Access current form
  const form = useFormContext();

  // Access any form globally
  const { getForm } = useFormRegistry();
  const otherForm = getForm('otherForm');

  // Access evaluation context
  const evalCtx = useEvaluationContext();
  const user = evalCtx.data.user;

  // Responsive design
  const { isMobile, up } = useBreakpoint();

  return <div>...</div>;
}
```

## Creating an Adapter

See `@galaxy-dev/metadsl-adapter-mui` for reference implementation.

```typescript
import { FieldTypeRegistry } from '@galaxy-dev/metadsl-runtime';
import { TextField } from 'your-ui-library';

// Register field component
FieldTypeRegistry.register({
  type: 'text',
  component: ({ value, onChange, label, error, helperText, ...props }) => (
    <TextField
      value={value || ''}
      onChange={(e) => onChange?.(e.target.value)}
      label={label}
      error={error}
      helperText={helperText}
      {...props}
    />
  ),
});
```

## Performance Optimizations

- **Field-level subscriptions** - Only re-render affected fields
- **Stable references** - `useCallback` with empty deps for context getters
- **Expression caching** - Cached evaluation results
- **Ref pattern** - Latest values without triggering re-renders

## License

MIT