@galaxy-dev/metadsl-runtime
v0.10.8
Published
MetaDSL runtime - Component-agnostic DSL renderer
Readme
@galaxy-dev/metadsl-runtime
Component-agnostic DSL runtime for MetaDSL.
Architecture
Core Design Principles
- Unified Evaluation Context - Scope chain system for expression evaluation
- Component Library Agnostic - Adapter pattern for different UI libraries
- Unified Form API - Single interface for local and global form access
- 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
pnpm add @galaxy-dev/metadsl-runtime @galaxy-dev/metadsl-coreCore Concepts
1. EvaluationContext - Scope Chain
Similar to JavaScript's scope chain, contexts inherit from parent:
<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:
// Inside form tree
function MyField() {
const form = useFormContext(); // DSLFormApi
const email = form.getValue('email');
form.setValue('email', '[email protected]');
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:
// 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
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
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
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.
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 -
useCallbackwith empty deps for context getters - Expression caching - Cached evaluation results
- Ref pattern - Latest values without triggering re-renders
License
MIT
