المزوّد
مزوّد واحد في جذر تطبيقك، مع الاتجاه والإعداد المحلي كخصائص. وجوده إلزامي، وكل ما يفعله مذكور في هذه الصفحة.
أين يوضع
في التخطيط الجذري، محيطًا بكل شيء. تأتي direction وlocale من المسار، ولا تُقرأ من DOM أبدًا.
import { TopClassProvider } from 'topclassui/provider'
import { ThemeScript } from 'topclassui/theme'
export default async function RootLayout({ children, params }: {
children: React.ReactNode
params: Promise<{ locale: string }>
}) {
const { locale } = await params
const dir = locale === 'ar' ? 'rtl' : 'ltr'
return (
<html lang={locale} dir={dir} data-theme="dark" suppressHydrationWarning>
<head><ThemeScript /></head>
<body>
<TopClassProvider direction={dir} locale={locale}>
{children}
</TopClassProvider>
</body>
</html>
)
}الخصائص
لماذا الاتجاه خاصية
قراءة document.dir داخل تأثير (effect) تعطي الخادم جوابًا والمتصفح جوابًا آخر لإطار واحد، فيظهر وميض بالاتجاه الخاطئ. أما الخاصية القادمة من التخطيط فلها القيمة نفسها في المكانين.
useEffect(() => {
setDir(document.documentElement.dir)
}, [])<html dir={dir}>
<TopClassProvider direction={dir}>ما الذي يعرضه
مزوّد الاتجاه
Select في الجهة الصحيحة بالعربية.منطقة الإشعارات
مزوّد التلميحات
جذر العزل
div عليه isolation: isolate، فتتراكب الطبقات فوق صفحتك بلا تعارض في z-index.ThemeScript
سكربت صغير مضمّن، يأتي أولًا في head، يقرأ التفضيل المحفوظ ويضبط data-theme قبل أول رسم. من دونه تُعرض الصفحة بالوضع الافتراضي ثم تتبدّل، فيظهر وميض بالوضع الخاطئ. السكربت نص ثابت، لذلك تستطيع سياسة أمان المحتوى (CSP) الصارمة أن تسمح به عبر البصمة أدناه.
import { ThemeScript } from 'topclassui/theme'
<head><ThemeScript /></head>Content-Security-Policy: script-src 'self' 'sha256-DXE/BJ+WKtAgobNXKiOEuUkho9yY2f/ky8nwg8sLL/8='في تطبيق صفحة واحدة
في تطبيق صفحة واحدة لا يعمل أي شيء يعرضه React قبل أول رسم، لذلك يوضع السكربت نفسه في index.html فوق سكربت الوحدة: الصق نص THEME_SCRIPT من topclassui/theme داخل وسم script. وتكون القيم الأولى لـ lang وdir وdata-theme سمات ثابتة على عنصر html. وعندما يغيّر الزائر اللغة، حدّث سمات html وخصائص المزوّد في الوقت نفسه.
<!doctype html>
<html lang="ar" dir="rtl" data-theme="dark">
<head>
<meta charset="UTF-8" />
<script>(function(){try{var m=["light","dark","ocean"];var t=null;try{t=localStorage.getItem('tc-theme')}catch(e){}if(!t||t==='system'||m.indexOf(t)<0){t=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}document.documentElement.dataset.theme=t}catch(e){}})()</script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>