{"id":"l-ds-3-4","courseId":"design-systems","lang":"ar","kind":"lesson","summary":"نظّم توثيق المكوّنات حول الطريقة التي يقرؤه بها الناس فعلًا، وولّد الأجزاء التي تنحرف تلقائيًا، واكتب الإرشاد الذي لا يقدّمه إلا البشر، مثل متى لا تستخدم مكوّنًا.","html":"<p>كان لموقع التوثيق الأول في Northwind 140 صفحة، وخط جميل، وقسم مبادئ استغرقت كتابته شهرًا. لكن التحليلات روت لنا قصة متواضعة: في صفحات المكوّنات كان وسيط مدّة الزيارة 38 ثانية. يصل الناس، ويمرّرون إلى أول كتلة كود، وينسخونها، ويغادرون. أما قسم المبادئ فكان متوسط زياراته تسعًا في الأسبوع، معظمها من فريقنا نحن.</p>\n<p>هذا ليس تقصيرًا من القرّاء. المهندسون والمصمّمون يفتحون التوثيق في منتصف مهمّة ومعهم سؤال واحد: «هل هذا هو المكوّن الصحيح، وكيف أستخدمه؟». التوثيق الجيد يجيب عن ذلك في الشاشة الأولى، ويُبقي كل ما عداه على بُعد تمريرة واحدة.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">تشريح صفحة المكوّن</h2>\n<p>كل صفحة مكوّن في Northwind تتبع الترتيب نفسه، فيتعلّم الناس أين ينظرون:</p>\n<ol>\n<li><strong>وصف من سطر واحد</strong> لما وُجد المكوّن من أجله.</li>\n<li><strong>متى تستخدمه، ومتى لا تستخدمه</strong>، مع روابط إلى البديل. «استخدم Dialog للقرارات التي توقف المهمّة الحالية. وللرسائل التي لا توقفها، استخدم Toast».</li>\n<li><strong>المثال الأساسي</strong>: عرض حيّ للاستخدام الصحيح الأكثر شيوعًا، مع كود قابل للنسخ.</li>\n<li><strong>أمثلة</strong> لكل variant ولكل حالة مهمّة، لكلٍّ منها كودها الخاص.</li>\n<li><strong>إمكانية الوصول</strong>: سلوك لوحة المفاتيح، وما تعلنه قارئات الشاشة، وفصل بين ما يتولّاه المكوّن وما يجب أن يفعله الفريق بنفسه (مثل «يجب أن تعطي كل Dialog عنصر <code dir=\"ltr\">Dialog.Title</code>»).</li>\n<li><strong>إرشادات المحتوى</strong>: كيف تكتب التسميات والرسائل. «تسميات الأزرار تبدأ بفعل: <em>Assign driver</em>، لا <em>Driver assignment</em>».</li>\n<li><strong>جدول الـ props</strong>، مولَّدًا من الكود.</li>\n<li><strong>الحالة والتاريخ</strong>: مستقر أو beta أو deprecated؛ والإصدار الذي أُضيف فيه؛ وروابط إلى الـ changelog.</li>\n</ol>\n<p>هذا الترتيب يتبع ما يحتاجه الناس تحت ضغط الوقت. القرار («هل أستخدم هذا؟») والمثال القابل للنسخ يأتيان أولًا؛ والمواد المرجعية تأتي أخيرًا.</p>\n<aside class=\"callout callout-why\" 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\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><circle cx=\"12\" cy=\"12\" r=\"6\"/><circle cx=\"12\" cy=\"12\" r=\"2\"/></svg><span><span class=\"callout-kind\">لماذا يهمّ هذا</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>لماذا يهمّ هذا</span></p>\n<p>المثال الأول في الصفحة يُنسخ أكثر من كل ما عداه مجتمعًا، فهو الذي يقرّر ما يُطلَق. كانت صفحة Button القديمة في Northwind تبدأ بزر primary. وسرعان ما ظهرت في الإنتاج صفحات فيها أربعة أزرار primary. وحين غيّرنا المثال الأول إلى زر secondary وزر primary جنبًا إلى جنب، بدأ الكود الجديد يتبع قاعدة «إجراء أساسي واحد في كل عرض» دون أن يُبلَّغ أحد.</p>\n</aside>\n<h2 id=\"sec-2\" tabindex=\"-1\">ولّد ما ينحرف، واكتب ما لا يمكن توليده</h2>\n<p>جزءان في صفحة التوثيق يتقادمان أسرع من غيرهما: جداول الـ props وأمثلة الكود. وكلاهما يمكن أن يأتي من الكود. جداول الـ props تُولَّد من أنواع TypeScript. والأمثلة تأتي من الـ stories، وهي الملفات نفسها المستخدمة في التطوير والاختبارات البصرية. في Storybook، ملف الـ story الذي يحمل الوسم <code dir=\"ltr\">autodocs</code> يحصل على صفحة توثيق مولَّدة فيها معاينة حيّة، وكود الـ story، وجدول controls مبني من الـ props الخاصة بالمكوّن:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"tsx\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Button.stories.tsx</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><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> type</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { Meta, StoryObj } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> '@storybook/react-vite'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { Button } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> './Button'</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\"> meta</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:#1F2328;--shiki-dark:#E6EDF3\">  component: Button,</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  tags: [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'autodocs'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">],</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  args: { children: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Assign driver'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> },</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">} </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">satisfies</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Meta</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">typeof</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> Button>;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> default</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> meta;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">type</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Story</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> StoryObj</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">typeof</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> meta>;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Secondary</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Story</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:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Primary</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Story</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { args: { variant: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'primary'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> } };</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Danger</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Story</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { args: { variant: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'danger'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, children: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'Delete route'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> } };</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Small</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Story</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { args: { size: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'sm'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> } };</span></span></code></pre></div>\n<p>ما لا يستطيع الكود توليده هو الحكم: متى تستخدم المكوّن، ومتى لا تستخدمه، وكيف تصوغ محتواه، ولماذا اتّخذ النظام قراراته. وهناك يذهب وقت الكتابة لدى فريق التوثيق.</p>\n<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>توثيق «كيف» دون «متى» أبدًا</span></p>\n<p>الصفحة التي تسرد كل prop ولا تقول أبدًا متى تختار المكوّن تنتج بالضبط إساءة الاستخدام التي كنت تحاول منعها. كان زر Danger في Northwind موثّقًا بإتقان، prop بعد prop، واستُخدم لـ «Remove filter» في تسع شاشات. سطر واحد في «متى لا تستخدمه» مع صورة افعل/لا تفعل أصلح الأمر خلال إصدار واحد.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">التوثيق جزء من «المنجَز»</h2>\n<p>التوثيق الذي يُطلَق لاحقًا لا يُطلَق أبدًا. قالب الـ pull request لمكوّنات النظام في Northwind فيه قائمة فحص: stories لكل variant وكل حالة، وصفحة توثيق محدّثة، وقسم لإمكانية الوصول، وإدخال في الـ changelog. وأي تغيير في مكوّن بدونها لا يُدمج. ولأن التوثيق يعيش في المستودع نفسه مع المكوّنات، يُراجَع في الـ pull request نفسه ومن الأشخاص أنفسهم.</p>\n<p>ثم عامل التوثيق كمنتج. تتابع Northwind ثلاث إشارات: عمليات البحث التي لا تعيد نتائج، والأسئلة المطروحة في قناة نظام التصميم على Slack، والصفحات التي ترتفع فيها نسبة المغادرة مباشرة بعد قسم «متى تستخدمه». كل سؤال متكرّر يصبح تغييرًا في التوثيق. وإن وصل السؤال نفسه ثلاث مرات، فمكان الإجابة هو الصفحة، لا سلسلة رسائل.</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>اكتب قسم «متى لا تستخدمه» أولًا</span></p>\n<p>حين توثّق مكوّنًا جديدًا، ابدأ بالحالات التي يكون فيها الخيار الخاطئ. هذا يجبرك على تسمية المكوّنات المجاورة وحدودها، وهي بالضبط المعلومة التي تنقص الناس حين يسيئون استخدام شيء.</p>\n</aside>\n<p>في التمرين تخطّط لإصلاحات التوثيق خلف إساءة استخدام حقيقية. وبهذا يكتمل قسم المكوّنات؛ وبعده تربط جانب التصميم بجانب الكود في النظام حتى يبقيا متزامنين.</p>\n","toc":[{"id":"sec-1","text":"تشريح صفحة المكوّن","level":2},{"id":"sec-2","text":"ولّد ما ينحرف، واكتب ما لا يمكن توليده","level":2},{"id":"sec-3","text":"التوثيق جزء من «المنجَز»","level":2}],"takeaways":["يمسح الناس التوثيق بحثًا عن مثال قابل للنسخ وعن إجابة بنعم أو لا على سؤال «هل أستخدم هذا؟»، فضع هذين أولًا.","كل صفحة مكوّن تحتاج قسمَي «متى تستخدمه» و«متى لا تستخدمه»، مع روابط إلى البديل الصحيح.","ولّد جداول الـ props والأمثلة من الكود والـ stories حتى لا تنحرف؛ واكتب يدويًا فقط ما لا يستطيع الكود التعبير عنه.","التوثيق جزء من تعريف «المنجَز»، ويُطلَق في الـ pull request نفسه الذي يحمل تغيير المكوّن."],"further":[{"title":"Writing docs with Autodocs (Storybook, official repository docs)","url":"https://github.com/storybookjs/storybook/blob/next/docs/writing-docs/autodocs.mdx"},{"title":"How Users Read on the Web (Nielsen Norman Group)","url":"https://www.nngroup.com/articles/how-users-read-on-the-web/"},{"title":"Button component page (U.S. Web Design System)","url":"https://designsystem.digital.gov/components/button/"}],"quiz":[{"q":"<p>تُظهر التحليلات أن معظم زوّار صفحة Button في Northwind يغادرون خلال 40 ثانية بعد نسخ أول مثال كود. ماذا تستنتج؟</p>","options":[{"text":"أن الصفحة فاشلة، ويجب إجبار الناس على قراءة الصفحة كاملة.","why":"الزيارات السريعة غالبًا نجاح، فقد وجد الزائر المثال الذي يحتاجه. وإجبار الناس على القراءة يعاكس طريقة عملهم."},{"text":"أن المثال الأول يجب أن يكون الاستخدام الصحيح الأكثر شيوعًا، مع أهم إرشاد بجانبه مباشرة.","why":"صحيح. إن كان المثال الأول هو ما يُنسخ، فهو الذي يقرّر ما يُطلَق، لذا يجب أن يقدّم القيمة الافتراضية الصحيحة."},{"text":"أن أمثلة الكود يجب أن تُحذف حتى يقرأ الناس الإرشادات.","why":"حذف أكثر ما يحتاجه الناس يدفعهم إلى النسخ من كود منتجات أخرى، بأخطائه."},{"text":"أن الصفحة تحتاج variants أكثر في المثال الأول.","why":"المثال الأول المزدحم أصعب في النسخ الصحيح؛ اعرض الحالة الشائعة أولًا والبقية تحتها."}],"answer":1},{"q":"<p>تستمرّ الفرق في استخدام زر Danger لإجراء «Remove filter»، وهو ليس إجراءً مدمّرًا. أيّ تغيير في التوثيق يساعد أكثر؟</p>","options":[{"text":"وصف أطول لألوان زر Danger.","why":"تفاصيل الألوان لا تخبر أحدًا متى يكون الـ variant مناسبًا."},{"text":"سطر في جدول الـ props لـ <code dir=\"ltr\">variant=&quot;danger&quot;</code>.","why":"جدول الـ props يُظهر أن الخيار موجود؛ ولا يقول شيئًا عن متى تختاره."},{"text":"ملاحظة «متى لا تستخدمه» مع مثال افعل/لا تفعل، تشير إلى الـ variant الثانوي للإجراءات القابلة للتراجع.","why":"صحيح. تسمّي إساءة الاستخدام بالضبط وتقدّم البديل لحظة اتخاذ القرار."}],"answer":2},{"q":"<p>جدول props الخاص بـ Button في التوثيق يسرد prop باسم <code dir=\"ltr\">kind</code> أُعيدت تسميته إلى <code dir=\"ltr\">variant</code> قبل إصدارين. ما الإصلاح الدائم؟</p>","options":[{"text":"تحديث الجدول يدويًا وإضافة تذكير إلى قائمة فحص الإصدار.","why":"قوائم الفحص تساعد، لكن الجداول التي تُصان يدويًا ستنحرف مجددًا مع إعادة التسمية التالية."},{"text":"حذف جدول الـ props والربط بالكود المصدري.","why":"كثير من القرّاء لا يرتاحون لقراءة كود المكوّنات، والجدول مفيد حين يكون صحيحًا."},{"text":"مراجعة كل صفحات التوثيق مرة كل ربع سنة.","why":"المراجعة الفصلية تجد الانحراف بعد شهور من تضليله للناس."},{"text":"توليد جدول الـ props من أنواع TypeScript الخاصة بالمكوّن أثناء بناء التوثيق.","why":"صحيح. الجدول المولَّد يتغيّر حين يتغيّر الكود، فلا يمكن أن يتأخّر عنه."}],"answer":3}],"exercise":{"kind":"choice","multiple":true,"options":["when-not","props-detail","first-example","principles","do-dont","slack"],"correct":["when-not","first-example","do-dont"],"title":"أصلح التوثيق الكامن خلف إساءة استخدام","prompt":"<p>يشتكي موظّفو الـ dispatch من أن التطبيق يقاطعهم باستمرار: ست فرق صارت تفتح Dialog يوقف العمل ويقول «Route saved!» بعد كل حفظ. تفحص صفحة توثيق Dialog، فتجدها تبدأ بعرض حيّ لنافذة النجاح هذه بالضبط، يليه جدول props كامل. ولا يوجد أي إرشاد عن متى تستخدم Dialog ومتى تستخدم Toast. أيّ التغييرات ستجريها؟ اختر كل ما ينطبق.</p>\n","hints":["تذكّر أيّ جزء من الصفحة يُنسخ أكثر من غيره.","الإصلاحات الجيدة تعمل لحظة يقرّر أحدهم أيّ مكوّن يستخدم، داخل صفحة التوثيق نفسها."],"explanation":"<p>المثال الأول هو أكثر كود يُنسخ في الصفحة، فقد كان يعلّم إساءة الاستخدام؛ واستبداله بقرار حقيقي يوقف العمل، مثل «Delete route?»، يغيّر ما يُنسخ. وسطر «متى لا تستخدمه» مع زوج افعل/لا تفعل يسمّيان الخطأ بالضبط ويشيران إلى Toast لحظة اتخاذ القرار. أما مزيد من تفاصيل الـ props، أو رابط إلى المبادئ، أو الردّ على الفرق واحدًا واحدًا في Slack، فتترك الصفحة نفسها بلا تغيير، فيكرّر الفريق التالي الخطأ.</p>\n","checkLabels":{},"optionText":{"when-not":{"text":"إضافة «متى لا تستخدمه: التأكيدات التي لا تحتاج قرارًا. استخدم Toast بدلًا منه» قرب أعلى الصفحة.","why":"صحيح. يسمّي إساءة الاستخدام والبديل حيث يقرّر الناس."},"props-detail":{"text":"توسيع جدول الـ props بتفاصيل أكثر عن <code dir=\"ltr\">open</code> و<code dir=\"ltr\">onOpenChange</code>.","why":"الـ props تعمل جيدًا؛ الفرق اختارت المكوّن الخطأ، وهذا ما لا يستطيع جدول الـ props معالجته."},"first-example":{"text":"استبدال المثال الأول بقرار يوقف العمل مثل «Delete route?» مع إجراءَي Cancel وDelete.","why":"صحيح. المثال الأول هو ما يُنسخ، لذا يجب أن يقدّم الاستخدام الصحيح."},"principles":{"text":"إضافة رابط إلى صفحة مبادئ التصميم في أعلى صفحة Dialog.","why":"المبادئ عامة؛ ولن يتبع أحد رابطًا ليعرف هل يجب أن توقف رسالة الحفظ الشاشة."},"do-dont":{"text":"إضافة زوج افعل/لا تفعل: Dialog لـ «Delete route?»، وToast لـ «Route saved».","why":"صحيح. الأمثلة المتجاورة تجعل الحدّ بين المكوّنين واضحًا من النظرة الأولى."},"slack":{"text":"الردّ على كل فريق من الفرق الست على Slack لشرح المشكلة.","why":"يساعد هذه الفرق الست مرة واحدة، لكن الصفحة تظلّ تعلّم الفريق التالي الخطأ نفسه."}}},"words":647,"readMinutes":4}