هدف التصدير الافتراضي لـ figmascope هو Jetpack Compose. لكن الحزمة مستقلة عن الوكيل — أنواع عقد IR وتنسيق الرموز ومراجع السلاسل تُعيَّن بنفس النظافة إلى React + Tailwind. كل ما عليك فعله هو إخبار الوكيل باستهداف JSX بدلاً من Kotlin.
يغطي هذا الدليل تعيين IR إلى JSX، وكيفية توسيع tailwind.config.js بالرموز من tokens.json، وأنماط المطالبات التي تُنتج أقل انحراف على الجانب React.
تحفظ مهم مقدماً
Compose هو ما تختبره figmascope أكثر. تم تصميم IR وتنسيق الرموز وقيود CONTEXT.md مع Compose في الاعتبار. React + Tailwind يعمل — يُعيَّن IR بشكل نظيف — لكنك ستلاحظ انحرافاً أكثر قليلاً، خاصة حول الطباعة وتخطيطات overlay. اِعلَم بأي شيء يبدو غير صحيح وأجرِ فحص رموز بعد الجولة الأولى.
الخطوة 1: توليد الحزمة وفك ضغطها
unzip ~/Downloads/context-bundle.zip -d ./design/
ls design/
# CONTEXT.md _meta.json components/ screens/ strings.json tokens.json
الخطوة 2: توسيع إعداد Tailwind برموز التصميم
قبل المطالبة، عيّن tokens.json إلى tailwind.config.js. هذه هي الخطوة الأساسية التي تجعل Tailwind مدركاً للرموز — بدلاً من قيم hex مُشفَّرة في سلاسل className، تحصل على أسماء دلالية تعود إلى التصميم.
// tailwind.config.js
const tokens = require('./design/tokens.json')
// بناء خريطة الألوان: { 'brand-7f5cfe': '#7F5CFE', ... }
const colors = Object.fromEntries(
Object.entries(tokens.color).map(([key, val]) => [
`brand-${key}`, val
])
)
// بناء خريطة التباعد: { 'ds-4': '4px', 'ds-8': '8px', ... }
const spacing = Object.fromEntries(
Object.entries(tokens.spacing).map(([key, val]) => [
`ds-${key}`, `${val}px`
])
)
// بناء خريطة نصف قطر الحدود
const borderRadius = Object.fromEntries(
Object.entries(tokens.radius).map(([key, val]) => [
`ds-${key}`, val === 9999 ? '9999px' : `${val}px`
])
)
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
colors,
spacing,
borderRadius,
}
}
}
ينتج هذا فئات Tailwind مثل bg-brand-7f5cfe وp-ds-16 وrounded-ds-12. ليست أجمل أسماء الفئات، لكنها قابلة للتتبع — كل فئة تعود إلى مفتاح رمز.
إذا كنت تفضّل أسماء دلالية، أضف طبقة تسمية:
// في theme.extend.colors:
primary: tokens.color['7f5cfe'],
background: tokens.color['f6f2ea'],
surface: tokens.color['ffffff'],
أعطِ الوكيل كليهما — إعداد الرمز الخام والأسماء الدلالية — حتى يتمكن من اختيار الاسم الصحيح في السياق.
الخطوة 3: مطالبة الوكيل باستهداف React + Tailwind
CONTEXT.md يقول أن الهدف الافتراضي هو Compose. تجاوز هذا صراحةً في مطالبتك:
نفّذ ./design/screens/home.json كمكوّن وظيفي React باستخدام Tailwind CSS.
تجاوز الإطار: تجاهل تعليمات Compose في CONTEXT.md. استهدف React + Tailwind.
القواعد:
- اقرأ ./design/tokens.json. الرموز مُوسَّعة إلى إعداد Tailwind —
استخدم فئات Tailwind المقابلة لمفاتيح الرموز (مثل bg-brand-7f5cfe وp-ds-16).
- سلاسل واجهة المستخدم تأتي من ./design/strings.json. استوردها وأشر إليها بالمفتاح.
- تعيين نوع عقد IR:
stack (axis:vertical) → <div className="flex flex-col gap-[Xpx]">
stack (axis:horizontal) → <div className="flex flex-row gap-[Xpx]">
overlay → <div className="relative"> مع أطفال ذات موضع مطلق
absolute → <div className="absolute" style={{"{{"}}top, left, width, height{{"}}"}}>
leaf (text) → <span> أو <p> مع فئات نص Tailwind
leaf (rectangle) → <div> مع فئات bg وrounded
- لا تُشفّر قيم hex. جميع الألوان يجب أن تستخدم فئات Tailwind من إعداد الرموز.
- لا تُشفّر السلاسل. استخدم مفاتيح strings.json.
الناتج إلى: src/screens/HomeScreen.tsx
تعيين IR إلى JSX
إليك جدول التعيين الكامل لـ React + Tailwind:
| نوع IR | الخصائص | نمط JSX |
|---|---|---|
stack | axis: "vertical" | <div className="flex flex-col gap-ds-{n}"> |
stack | axis: "horizontal" | <div className="flex flex-row gap-ds-{n}"> |
overlay | أطفال متراكبة | <div className="relative"> مع أطفال className="absolute ..." |
absolute | x، y، w، h | <div className="absolute" style={{"{{"}}top: y, left: x, width: w, height: h{{"}}"}}> |
leaf | type: "text" | <span className="text-{size} font-{weight} leading-{lh} text-brand-{color}"> |
leaf | type: "rectangle" | <div className="bg-brand-{color} rounded-ds-{r}"> |
قيم Gap والحشو: استخدم فئات تباعد ds-{n} من توسيع إعداد Tailwind. إذا لم تكن قيمة gap مفتاح رمز نظيف، استخدم صيغة القيمة التعسفية في Tailwind: gap-[20px].
مثال حقيقي: من IR شاشة رئيسية إلى JSX
باستخدام نفس IR من جولة Compose:
import strings from '../../design/strings.json'
export function HomeScreen() {
return (
<div className="flex flex-col gap-ds-24 p-ds-16 bg-brand-f6f2ea min-h-screen">
<h1 className="text-2xl font-bold leading-tight text-brand-1a1a2e">
{strings['home.title'].value}
</h1>
<div className="flex flex-col gap-ds-12">
<div className="bg-white rounded-ds-12 p-ds-16">
<span className="text-xs font-medium text-brand-7f5cfe">
{strings['home.card.label'].value}
</span>
</div>
</div>
</div>
)
}
كل className قابلة للتتبع. gap-ds-24 → spacing.24 → 24px. text-brand-7f5cfe → color.7f5cfe → #7F5CFE. إذا انحرفت قيمة (مثلاً كتب الوكيل gap-6 بدلاً من gap-ds-24)، يظهر هذا فوراً في مراجعة الكود.
لماذا يعمل tokens.json + إعداد Tailwind
كلا النظامين مبني على الرموز أولاً. Tailwind يوسّع إعداد أساسي بقيم مخصصة؛ tokens.json مُهيكَل فعلاً كخريطة قيم مخصصة. خطوة التوسيع (الخطوة 2 أعلاه) إعداد لمرة واحدة — بعدها يستخدم الوكيل أسماء فئات Tailwind المرتبطة دلالياً بنظام التصميم بدلاً من فئات مساعدة تعسفية.
النتيجة: عند تغيير رمز التصميم (لنقل تحوّل اللون الأساسي من #7F5CFE إلى #6B4EE6)، تحدّث قيمة واحدة في tokens.json، تُعيد تشغيل استيراد الإعداد، ويُعيد Tailwind التوليد. كود المكوّن لا يتغيّر.
فحص انحراف الرموز
بعد التنفيذ، اطلب من الوكيل تدقيق الانحراف:
دقّق src/screens/HomeScreen.tsx لانحراف الرموز.
تحقق من:
1. أي قيم لون hex غير مُحال إليها عبر فئة Tailwind من إعداد الرموز.
2. أي قيم px أو rem مُشفَّرة يجب أن تكون فئات ds-{n}.
3. أي سلاسل واجهة مستخدم غير مُستمدّة من design/strings.json.
أدرج المخالفات. أنتج diff يُصلحها.
Overlay وAbsolute — الحالات الصعبة
عقد Overlay تحتاج أصلاً بـ relative وأطفالاً بـ absolute. يُدرج IR الأطفال بترتيب z (الأول = الطبقة السفلية). أخبر الوكيل بالحفاظ على هذا الترتيب في JSX — React يُصيَّر بترتيب DOM وCSP position: absolute يُكدّس وفقاً لذلك.
عقد Absolute تستخدم إحداثيات بكسل خام من Figma. هذه تأتي تقريباً دائماً من تصاميم لم تُبنَ بـ auto-layout. إذا كنت ترى كثيراً من عقد absolute، عادةً ما يعني هذا أن ملف Figma فيه تموضع يدوي — الكود المولّد سيكون هشاً عند أحجام viewport مختلفة. فكّر في الإشارة لهذا وإعادة الهيكلة إلى تخطيطات flex.
التعامل مع السلاسل في React
على خلاف Android (حيث تُعيَّن مفاتيح strings.json إلى معرّفات موارد R.string.*)، في React تستورد JSON مباشرة:
import strings from '../../design/strings.json'
// الاستخدام
{strings['home.title'].value}
// أو مع احتياط
{strings['home.title']?.value ?? strings['home.title']?.fallback ?? 'Untitled'}
إذا كنت تستخدم مكتبات i18n (react-i18next وnext-intl)، مفاتيح تدوين النقطة في strings.json تُعيَّن مباشرة إلى مساحات أسماء مفاتيح الترجمة. أخبر الوكيل أي مكتبة i18n تستخدم حتى يولّد نمط الاستدعاء الصحيح.
الفجوات الصادقة على الجانب React
أدوات الطباعة. أدوات نص Tailwind (text-xs وtext-2xl) لا تُعيَّن 1:1 إلى رموز typography في tokens.json. Tailwind لديه مقياس نوع ثابت؛ ملف الرموز له أحجام تعسفية. ستحتاج إما لتوسيع إعداد fontSize في Tailwind بقيم الرموز أو استخدام قيم تعسفية (text-[24px]). كلاهما يعمل؛ توسيع الإعداد أنظف.
ارتفاع السطر. نفس المشكلة — أدوات leading في Tailwind لا تتطابق مع قيم lineHeight التعسفية. استخدم leading-[{value}] أو وسّع الإعداد.
التدرجات. غير مدعومة في IR. أي ملء تدرج يظهر كتحذير في _meta.json ومحذوف من خاصية fill للعقدة. تعامل معه يدوياً.
لا شيء من هذا عائق — إنها فجوات معروفة. الأساس المدرك للرموز متين؛ الحواف فقط تحتاج تعاملاً يدوياً.
ابدأ بـ figmascope لتصدير حزمتك، ثم استخدم هذا الدليل مع سير عمل Cursor أو سير عمل Claude Code لقيادة التنفيذ.