{"id":"l-ds-2-2","courseId":"design-systems","lang":"ar","kind":"lesson","summary":"سمِّ الـ design tokens وفق قواعد مكتوبة من فئة ومفهوم وخاصية وvariant وحالة، حتى تبقى الأسماء صادقة مع الوضع الداكن والعلامات الجديدة وسنوات من النمو.","html":"<p>كان في ملف الـ tokens القديم في Northwind token اسمه <code dir=\"ltr\">--color-blue-new</code>. بعد سنتين صار هناك أيضًا <code dir=\"ltr\">--color-blue-new-2</code> و<code dir=\"ltr\">--color-blue-newer</code>. ولم يعرف أحد أيّها أزرق العلامة. التسمية هي الجزء من نظام التصميم الذي يبدو جدالًا على التوافه، ثم يتبيّن أنه معمارية: فالأسماء هي الـ API الذي يكتبه كل مصمّم ومهندس مئات المرات في الأسبوع.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">قواعد، لا قائمة</h2>\n<p>الأسماء الجيدة للـ tokens تأتي من قواعد: مجموعة ثابتة من الأجزاء بترتيب ثابت. والـ semantic tokens في Northwind تتبع هذه القواعد:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Text</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code>--nw-{category}-{concept}-{property}-{variant}-{state}\n\n--nw-color-action-bg                 category=color concept=action property=bg\n--nw-color-action-bg-hover           … state=hover\n--nw-color-danger-text               concept=danger property=text\n--nw-color-text-subtle               concept=text variant=subtle\n--nw-space-inset-md                  category=space concept=inset variant=md\n--nw-radius-control                  category=radius concept=control</code></pre></div>\n<p>ليس كل token يستخدم كل الأجزاء، لكن الأجزاء الموجودة تأتي دائمًا بهذا الترتيب. وهذا يمنحك أمرين. يستطيع الناس تخمين أسماء لم يروها قط: إن كان <code dir=\"ltr\">--nw-color-action-bg-hover</code> موجودًا، فالأرجح أن <code dir=\"ltr\">--nw-color-danger-bg-hover</code> موجود أيضًا. وحين تُرتَّب أبجديًا، تتجمّع الـ tokens المترابطة معًا في كل محرّر وفي لوحة المتغيّرات في Figma.</p>\n<p>البادئة <code dir=\"ltr\">nw</code> نطاق أسماء (namespace). تمنع التصادم مع CSS من أطراف خارجية، وتجعل tokens النظام سهلة البحث، وهذا ما ستستخدمه لاحقًا في مقاييس التبنّي.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">سمِّ الغرض، لا المظهر</h2>\n<p>في طبقة الـ primitives تكون تسمية المظهر صحيحة: <code dir=\"ltr\">--nw-blue-600</code> <em>هو</em> أزرق فعلًا. أما في الطبقة الدلالية فالمظهر هو بالضبط ما تغيّره الـ themes، لذا يجب أن تصف الأسماء الغرض.</p>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"جدول قابل للتمرير\" tabindex=\"0\"><table><thead>\n<tr>\n<th>اسم هشّ</th>\n<th>لماذا ينكسر</th>\n<th>اسم متين</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code dir=\"ltr\">--nw-color-red-bg</code></td>\n<td>لون الخطأ في Tidewater برتقالي</td>\n<td><code dir=\"ltr\">--nw-color-danger-bg</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">--nw-color-text-light</code></td>\n<td>في الوضع الداكن ليس فاتحًا</td>\n<td><code dir=\"ltr\">--nw-color-text-subtle</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">--nw-color-header-bg</code></td>\n<td>مسمّى باسم أول مستخدم له</td>\n<td><code dir=\"ltr\">--nw-color-surface-inverse</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">--nw-color-text-2</code></td>\n<td>لا يقول شيئًا</td>\n<td><code dir=\"ltr\">--nw-color-text-muted</code></td>\n</tr>\n</tbody>\n</table></div><aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>تسمية الـ token باسم أول مكان يظهر فيه</span></p>\n<p>الـ token المسمّى <code dir=\"ltr\">header-bg</code> يدعو فريق الشريط الجانبي إما إلى إساءة استخدامه أو إلى تكراره. قبل أن تسمّي semantic token، اسأل عن <em>الدور</em> الذي تؤدّيه القيمة، وهل يمكن لمكوّن آخر أن يؤدّي الدور نفسه. إن كانت الإجابة نعم، فسمِّ الدور.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">السلالم: أرقام أم مقاسات</h2>\n<p>سلالم الـ primitives تحتاج أيضًا إلى نظام تسمية. وهناك خياران شائعان:</p>\n<ul>\n<li><strong>رقمي</strong>، مثل <code dir=\"ltr\">100</code> إلى <code dir=\"ltr\">900</code> لدرجة سطوع اللون، أو <code dir=\"ltr\">1</code> إلى <code dir=\"ltr\">12</code> لخطوات المسافات. يمكنك إدراج <code dir=\"ltr\">150</code> لاحقًا دون إعادة تسمية أي شيء. والأرقام وحدها لا تحمل معنى كبيرًا.</li>\n<li><strong>مقاسات الملابس</strong>، مثل <code dir=\"ltr\">xs</code> و<code dir=\"ltr\">sm</code> و<code dir=\"ltr\">md</code> و<code dir=\"ltr\">lg</code> و<code dir=\"ltr\">xl</code>. سهلة القراءة في مراجعة الكود. لكن حين يحتاج المصمّمون إلى خطوة بين <code dir=\"ltr\">sm</code> و<code dir=\"ltr\">md</code> تعلق بأسماء مثل <code dir=\"ltr\">sm-plus</code>.</li>\n</ul>\n<p>تستخدم Northwind السلالم الرقمية للـ primitives، ومقاسات الملابس لحفنة tokens المسافات الدلالية (<code dir=\"ltr\">--nw-space-inset-sm</code> و<code dir=\"ltr\">-md</code> و<code dir=\"ltr\">-lg</code>)، لأن المصمّمين يفكّرون بالمقاسات وهذه المجموعة نادرًا ما تكبر. اختر نظامًا واحدًا لكل سُلّم والتزم به. أما الخلط بينهما داخل سُلّم واحد، مثل <code dir=\"ltr\">--nw-space-2</code> و<code dir=\"ltr\">--nw-space-md</code> و<code dir=\"ltr\">--nw-space-24px</code>، فهو أسرع طريق إلى سُلّم لا يثق به أحد، لأن الناس لم يعودوا يميّزون أيّ القيم أشقاء.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">افرض القواعد</h2>\n<p>القواعد التي تعيش فقط في صفحة wiki تصمد حتى أول مساهم مستعجل. حوّلها إلى فحص يعمل في الـ CI:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-run=\"js\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">JavaScript</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"js\" data-index=\"1\" aria-label=\"شغّل هذا المثال\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>تشغيل</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> grammar</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> /</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">^</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">--nw-(color</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">space</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">radius</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">font</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">shadow</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">motion)(-</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">[a-z]</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">(-</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">[0-9]</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?$</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">/</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> banned</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> /-(red</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">blue</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">green</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">light</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">dark</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">new</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">old</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">[0-9]</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">px)(-</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">|$</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">)/</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> proposed</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">  '--nw-color-action-bg-hover'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">  '--nw-color-text-light'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">  '--nw-color-blue-new'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">  '--nw-space-inset-md'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">  '--nwColorDangerText'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">  '--nw-color-danger-text'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">];</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> name</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> of</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> proposed) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> ok</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> grammar.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">test</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(name) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">&#x26;&#x26;</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> !</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">banned.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">test</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(name);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  console.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">log</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(ok </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'ok    '</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'reject'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, name);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre><div class=\"run-output\" data-run-output=\"1\" hidden></div></div>\n<p>قائمة <code dir=\"ltr\">banned</code> تلتقط العادات التي تنكسر أولًا: أسماء الألوان، و«light» و«dark»، و«new» و«old»، وقيم البكسل الخام. شغّلها على كل ملف tokens في الـ pull requests، واطبع القاعدة التي فشلت حتى يتعلّم المساهمون القواعد من رسالة الخطأ لا من صفحة wiki. إنها أداة فظّة، وسترفض أحيانًا اسمًا جيدًا. لا بأس بذلك؛ فالمساهم الذي يصطدم بها يسأل فريق النواة، والحوار نفسه هو المقصود.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">نصيحة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>الأسماء في ملفات الـ tokens مقابل CSS</span></p>\n<p>في ملف JSON بصيغة DTCG تصبح أجزاء الاسم مجموعات متداخلة: <code dir=\"ltr\">color</code> ← <code dir=\"ltr\">action</code> ← <code dir=\"ltr\">bg</code> ← <code dir=\"ltr\">hover</code>. ويصلها خط الإنتاج بشَرطات ويضيف البادئة حين يكتب الـ CSS. والصيغة تحجز <code dir=\"ltr\">.</code> للمراجع مثل <code dir=\"ltr\">{color.action.bg}</code>، ولهذا لا يمكن أن تحتوي أسماء الـ tokens والمجموعات على نقاط. سترى هذا بعد درسين.</p>\n</aside>\n<h2 id=\"sec-5\" tabindex=\"-1\">إعادة التسمية دون كسر عمل الآخرين</h2>\n<p>ستخطئ في بعض الأسماء؛ الجميع يخطئ. حين تعيد تسمية token، أبقِ الاسم القديم اسمًا مستعارًا (alias) للجديد لإصدار واحد على الأقل، وعلّمه كـ deprecated (مُهمَل)، وأعلن ذلك في الـ changelog. يغطّي القسم 4 مسار الـ deprecation كاملًا. في التمرين التالي تراجع دفعة من الأسماء المقترحة كما يفعل فريق النواة في Northwind كل أسبوع. وبعدها تشغّل الطبقة الدلالية: مجموعة مكوّنات واحدة، وعدّة themes.</p>\n","toc":[{"id":"sec-1","text":"قواعد، لا قائمة","level":2},{"id":"sec-2","text":"سمِّ الغرض، لا المظهر","level":2},{"id":"sec-3","text":"السلالم: أرقام أم مقاسات","level":2},{"id":"sec-4","text":"افرض القواعد","level":2},{"id":"sec-5","text":"إعادة التسمية دون كسر عمل الآخرين","level":2}],"takeaways":["أسماء الـ semantic tokens تصف الغرض (<code dir=\"ltr\">danger</code>، <code dir=\"ltr\">subtle</code>) ولا تصف المظهر (<code dir=\"ltr\">red</code>، <code dir=\"ltr\">light</code>) أبدًا، لأن المظهر يتغيّر مع الـ themes.","الترتيب الثابت لأجزاء الاسم، مثل category-concept-property-variant-state، يجعل الـ tokens سهلة التخمين وسهلة الترتيب.","السلالم الرقمية مثل 100 إلى 900 تترك مجالًا لإدراج قيم لاحقًا؛ أما مقاسات الملابس فأسهل قراءة لكنها تمتلئ.","اكتب قواعد التسمية وافرضها بقاعدة lint، وإلا اخترع كل مساهم قواعده الخاصة."],"further":[{"title":"Custom properties (--*) (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/--*"},{"title":"Design tokens (Material Design 3)","url":"https://m3.material.io/foundations/design-tokens"},{"title":"Design Tokens Format Module 2025.10 (source on GitHub)","url":"https://github.com/design-tokens/community-group"}],"quiz":[{"q":"<p>أيّ اسم semantic token سيبقى دقيقًا بعد أن تضيف Northwind الوضع الداكن؟</p>","options":[{"text":"<code dir=\"ltr\">--nw-color-text-subtle</code>","why":"صحيح. كلمة «subtle» تصف الدور (نص أقل بروزًا)، وهذا يصحّ في الـ theme الفاتح والداكن على حدّ سواء."},{"text":"<code dir=\"ltr\">--nw-color-text-light</code>","why":"في الوضع الداكن يكون النص الأقل بروزًا رماديًا متوسطًا على خلفية داكنة، فإما أن تكذب كلمة «light» أو تختلط باسم الـ theme."},{"text":"<code dir=\"ltr\">--nw-color-text-gray-500</code>","why":"تضمين primitive في اسم دلالي يعني أن الاسم ينكسر في اللحظة التي يربطه فيها الـ theme برمادي مختلف."},{"text":"<code dir=\"ltr\">--nw-color-text-2</code>","why":"الرقم المجرّد لا يقول شيئًا عن الغرض، فلن يستطيع أحد اختياره بشكل صحيح دون فتح التوثيق."}],"answer":0},{"q":"<p>أنشأ فريق الـ dispatch الـ token المسمّى <code dir=\"ltr\">--nw-color-header-bg</code> للشريط العلوي. والآن يحتاج الشريط الجانبي إلى اللون نفسه. ما أفضل خطوة؟</p>","options":[{"text":"استخدام <code dir=\"ltr\">--nw-color-header-bg</code> في الشريط الجانبي أيضًا.","why":"يصبح الشريط الجانبي معتمدًا على token مسمّى باسم الترويسة؛ وحين تتغيّر الترويسة يتغيّر الشريط الجانبي عن غير قصد."},{"text":"نسخ القيمة إلى token جديد باسم <code dir=\"ltr\">--nw-color-sidebar-bg</code>.","why":"اثنان من الـ tokens لقرار واحد سيتباعدان، وهكذا بالضبط ظهرت الدرجات الرمادية الأربع والستون."},{"text":"إعادة تسميته إلى token مبني على الغرض مثل <code dir=\"ltr\">--nw-color-surface-inverse</code>، وجعل الاسم القديم اسمًا مستعارًا (alias) له خلال فترة الـ deprecation.","why":"صحيح. صار الاسم يصف الدور المشترك، والاسم المستعار يمنح المستخدمين وقتًا للانتقال."}],"answer":2},{"q":"<p>سُلّم المسافات لديك هو <code dir=\"ltr\">--nw-space-sm</code> و<code dir=\"ltr\">-md</code> و<code dir=\"ltr\">-lg</code>. يحتاج المصمّمون الآن إلى قيمة بين <code dir=\"ltr\">sm</code> و<code dir=\"ltr\">md</code>. ماذا يكشف هذا؟</p>","options":[{"text":"أن مقاسات الملابس يجب ألا تُستخدم للـ tokens أبدًا.","why":"هي مقروءة وتعمل جيدًا مع السلالم الصغيرة المستقرّة؛ المشكلة فقط أنها يصعب توسيعها من الوسط."},{"text":"أن القيمة الجديدة يجب أن تكون قيمة بكسل منفردة داخل ذلك المكوّن.","why":"القيمة المكتوبة يدويًا تتجاوز السُلّم وتبدأ الانحراف من جديد."},{"text":"أن tokens المسافات يجب أن تكون component tokens بدلًا من ذلك.","why":"المسافات مشتركة بين المكوّنات، فمكانها السُلّم المشترك."},{"text":"أن الدرجات المسمّاة تمتلئ؛ أما السُلّم الرقمي مثل 100 و200 و300 فيترك مجالًا لإضافة 150 لاحقًا.","why":"صحيح. السلالم الرقمية تضحّي بشيء من سهولة القراءة مقابل مجال للنمو، ولهذا تستخدمها أنظمة كثيرة للـ primitives."}],"answer":3},{"q":"<p>لماذا تمنع صيغة DTCG وجود <code dir=\"ltr\">.</code> داخل أسماء الـ tokens؟</p>","options":[{"text":"لأن النقاط غير مسموحة في مفاتيح JSON.","why":"مفاتيح JSON يمكن أن تحتوي أي نص، بما فيه النقاط."},{"text":"لأن النقطة تفصل أجزاء المسار في المراجع مثل <code dir=\"ltr\">{color.action.bg}</code>.","why":"صحيح. النقطة داخل الاسم ستجعل مسار المرجع ملتبسًا."},{"text":"لأن الـ CSS custom properties لا يمكن أن تحتوي نقاطًا.","why":"القاعدة آتية من صيغة المراجع في تنسيق الـ tokens، لا من CSS."}],"answer":1}],"exercise":{"kind":"choice","multiple":true,"options":["success-border","orange-badge","text-inverse","modal-shadow-v2","focus-ring","dark-surface"],"correct":["success-border","text-inverse","focus-ring"],"title":"راجع اقتراحات الـ tokens لهذا الأسبوع","prompt":"<p>اقتُرحت ستة أسماء semantic tokens على Northwind UI هذا الأسبوع. يجب أن يدعم النظام الـ theme الفاتح والداكن وعلامتين (Northwind وTidewater)، ويتبع القواعد <code dir=\"ltr\">--nw-{category}-{concept}-{property}-{variant}-{state}</code>. اختر كل اسم <strong>توافق عليه كما هو مكتوب</strong>.</p>\n","hints":["تخيّل كل اسم في الوضع الداكن وفي علامة Tidewater. هل ما زال يقول الحقيقة؟","انتبه لأسماء الألوان، وكلمات الـ theme، وأرقام الإصدارات، والأسماء التي لا تناسب إلا مكوّنًا واحدًا."],"explanation":"<p>الأسماء المقبولة تصف دورًا: حدّ رسائل النجاح، والنص على سطح معكوس، وحلقة التركيز. وكلٌّ منها يبقى دقيقًا في كل theme وكل علامة. أما <code dir=\"ltr\">orange-badge</code> فيصف مظهرًا ستغيّره لوحة ألوان Tidewater، و<code dir=\"ltr\">modal-shadow-v2</code> يسجّل التاريخ بدل الغرض (وإعادة التصميم القادمة ستعطيك <code dir=\"ltr\">v3</code>)، و<code dir=\"ltr\">dark-surface</code> ينكسر في الوضع الداكن حيث معظم الأسطح داكنة. والبديل المبني على الدور سيكون <code dir=\"ltr\">--nw-color-surface-raised</code> أو <code dir=\"ltr\">--nw-color-surface-inverse</code>.</p>\n","checkLabels":{},"optionText":{"success-border":{"text":"<code dir=\"ltr\">--nw-color-success-border</code>","why":"موافقة. يسمّي دورًا (حدّ رسائل النجاح) ويتبع ترتيب القواعد."},"orange-badge":{"text":"<code dir=\"ltr\">--nw-color-orange-badge-bg</code>","why":"رفض. «Orange» وصف للمظهر؛ وحين يتغيّر لون التحذير في Tidewater يصبح الاسم كاذبًا."},"text-inverse":{"text":"<code dir=\"ltr\">--nw-color-text-inverse</code>","why":"موافقة. «Inverse» تعني النص على السطح المعاكس، وهذا يصحّ في الـ theme الفاتح والداكن."},"modal-shadow-v2":{"text":"<code dir=\"ltr\">--nw-shadow-modal-v2</code>","why":"رفض. رقم الإصدار يسجّل التاريخ لا الغرض، ويضمن ظهور <code dir=\"ltr\">v3</code> لاحقًا."},"focus-ring":{"text":"<code dir=\"ltr\">--nw-color-focus-ring</code>","why":"موافقة. كل المكوّنات التفاعلية تتشارك حلقة التركيز، والدور ثابت عبر الـ themes."},"dark-surface":{"text":"<code dir=\"ltr\">--nw-color-dark-surface</code>","why":"رفض. في الوضع الداكن تكون معظم الأسطح داكنة، فيفقد الاسم أي معنى."}}},"words":608,"readMinutes":4}