hero-dynamic-freamwork
v1.0.0
Published
Event orchestration layer for Formily JSON schemas.
Readme
Formily Event Framework with Global State Management
یک لایه رویدادی (Event Layer) برای Formily با قابلیت مدیریت state گلوبال.
ویژگیها
- ✅ اضافه کردن event handler های پویا به JSON Schema
- ✅ مدیریت خطا و دیباگ آسان
- ✅ Global State Management با
$global - ✅ Reactive state updates
- ✅ TypeScript support
- ✅ React hooks برای دسترسی به state
نصب
npm install freamwork-formilyاستفاده سریع
1. راهاندازی اولیه
import { EventRuntime, EventRuntimeProvider, GlobalStateManager } from 'freamwork-formily';
// ایجاد global state با مقادیر اولیه
const globalState = new GlobalStateManager({
page1: {
name: '',
counter: 0
}
});
// ایجاد runtime
const runtime = new EventRuntime({
globalState,
onError(error, meta) {
console.error('Event error:', error, meta);
}
});
function App() {
return (
<EventRuntimeProvider runtime={runtime}>
{/* اپلیکیشن شما */}
</EventRuntimeProvider>
);
}2. استفاده از $global در Schema
{
"type": "object",
"properties": {
"username": {
"type": "string",
"title": "نام کاربری",
"x-component": "Input",
"x-component-props": {
"events": [
{
"onChange": "{{$global.page1.name = event.target.value}}"
}
]
}
},
"submitButton": {
"type": "void",
"x-component": "Button",
"x-component-props": {
"children": "ثبت",
"events": [
{
"onClick": "{{console.log('نام کاربر:', $global.page1.name)}}"
}
]
}
}
}
}3. دسترسی به Global State در React
import { useGlobalState } from 'freamwork-formily';
function MyComponent() {
const globalState = useGlobalState();
const [name, setName] = useState('');
useEffect(() => {
// Subscribe به تغییرات
const unsubscribe = globalState.subscribe((state) => {
setName(state.page1?.name || '');
});
return unsubscribe;
}, [globalState]);
const updateName = () => {
globalState.setState('page1.name', 'John Doe');
};
return (
<div>
<p>Name: {name}</p>
<button onClick={updateName}>Update Name</button>
</div>
);
}API Reference
GlobalStateManager
Constructor
const globalState = new GlobalStateManager(initialState);Methods
getState()
دریافت کل state object
const state = globalState.getState();setState(path, value)
تنظیم مقدار با dot notation
globalState.setState('user.profile.name', 'John');
globalState.setState('counter', 42);getStateValue(path)
دریافت مقدار با dot notation
const name = globalState.getStateValue('user.profile.name');merge(newState)
ادغام state جدید با state موجود
globalState.merge({
page2: { title: 'New Page' }
});reset(newState)
جایگزینی کامل state
globalState.reset({
page1: { name: '', counter: 0 }
});clear()
پاک کردن تمام state
globalState.clear();subscribe(listener)
گوش دادن به تغییرات state
const unsubscribe = globalState.subscribe((state) => {
console.log('State changed:', state);
});
// برای لغو subscription:
unsubscribe();EventRuntime
Constructor Options
interface EventRuntimeOptions {
defaults?: Partial<EventExecutionContext>;
onError?: (error: unknown, meta: EventHandlerMeta & { code: string }) => void;
globalState?: GlobalStateManager;
}مثال:
const runtime = new EventRuntime({
globalState: new GlobalStateManager({
user: { isLoggedIn: false }
}),
defaults: {
scope: {
logger: console,
api: myApiClient
}
},
onError(error, meta) {
console.error('Runtime error:', error);
// ارسال به سیستم لاگ
}
});React Hooks
useEventRuntime()
const runtime = useEventRuntime();
const globalState = runtime.getGlobalState();useGlobalState()
const globalState = useGlobalState();مثالهای پیشرفته
مثال 1: فرم با Validation
{
"properties": {
"email": {
"type": "string",
"title": "ایمیل",
"x-component": "Input",
"x-component-props": {
"events": [
{
"onChange": "{{$global.form.email = event.target.value}}",
"onBlur": "{{const isValid = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test($global.form.email); $global.form.emailValid = isValid; console.log('Email valid:', isValid)}}"
}
]
}
}
}
}مثال 2: شمارنده با History
{
"x-component-props": {
"events": [
{
"onClick": "{{const newValue = ($global.counter || 0) + 1; $global.counter = newValue; $global.history = [...($global.history || []), newValue]; console.log('Counter history:', $global.history)}}"
}
]
}
}مثال 3: دسترسی به API
const runtime = new EventRuntime({
defaults: {
scope: {
api: {
async fetchUser(id) {
const response = await fetch(\`/api/users/\${id}\`);
return response.json();
}
}
}
},
globalState: new GlobalStateManager({
users: {}
})
});{
"x-component-props": {
"events": [
{
"onClick": "{{scope.api.fetchUser(123).then(user => { $global.users[user.id] = user; })}}"
}
]
}
}مثال 4: کامپوننت با Realtime Updates
function RealtimeCounter() {
const globalState = useGlobalState();
const [counter, setCounter] = useState(0);
useEffect(() => {
const unsubscribe = globalState.subscribe((state) => {
setCounter(state.counter || 0);
});
// Initial value
setCounter(globalState.getStateValue('counter') || 0);
return unsubscribe;
}, [globalState]);
return (
<div>
<h2>Counter: {counter}</h2>
<p>این شمارنده به صورت خودکار با تغییرات global state بهروز میشود</p>
</div>
);
}متغیرهای در دسترس در Event Handlers
در event handler های schema، متغیرهای زیر در دسترس هستند:
$global- Global state objectevent- Event payloadform- Formily form instancefield- Current field instancescope- Custom scope objectschema- Current schema nodepath- Field pathmeta- Additional metadata
Best Practices
1. ساختار State
// ✅ خوب - ساختار سازماندهی شده
const globalState = new GlobalStateManager({
ui: {
theme: 'light',
sidebar: { collapsed: false }
},
data: {
users: {},
products: {}
},
temp: {
searchQuery: ''
}
});
// ❌ بد - flat و نامرتب
const globalState = new GlobalStateManager({
theme: 'light',
collapsed: false,
users: {},
searchQuery: ''
});2. Error Handling
const runtime = new EventRuntime({
globalState,
onError(error, meta) {
// لاگ کردن خطا
console.error('Event error:', {
error,
path: meta.path,
eventName: meta.eventName,
code: meta.code
});
// ذخیره در monitoring service
if (window.Sentry) {
window.Sentry.captureException(error, {
extra: meta
});
}
}
});3. TypeScript Support
interface AppGlobalState {
user: {
id: string;
name: string;
isLoggedIn: boolean;
};
ui: {
theme: 'light' | 'dark';
language: 'en' | 'fa';
};
}
const globalState = new GlobalStateManager<AppGlobalState>({
user: {
id: '',
name: '',
isLoggedIn: false
},
ui: {
theme: 'light',
language: 'fa'
}
});4. Cleanup در Components
useEffect(() => {
const unsubscribe = globalState.subscribe(listener);
// حتماً cleanup کنید
return () => {
unsubscribe();
};
}, [globalState]);مشکلات رایج
مشکل: تغییرات state اعمال نمیشود
// ❌ اشتباه - مستقیماً به object اصلی دسترسی
const state = globalState.getState();
state.counter = 10; // این کار نمیکند!
// ✅ درست - از setState استفاده کنید
globalState.setState('counter', 10);مشکل: Nested objects بهروز نمیشوند
// ✅ درست - از dot notation استفاده کنید
globalState.setState('user.profile.name', 'John');
// یا از merge استفاده کنید
globalState.merge({
user: {
...globalState.getStateValue('user'),
profile: {
...globalState.getStateValue('user.profile'),
name: 'John'
}
}
});مجوز
ISC
مشارکت
مشارکتها استقبال میشود! لطفاً یک issue یا pull request باز کنید.
