درخت ناوبری (NavTree)
لایهی ناوبری تودرتو با گروههای قابلجمعشدن، کاسکید حالت فعال، و indent خودکار — لایهی v2 روی Sidebar primitive
معرفی
NavTree لایهی composition ناوبری است که روی primitive های Sidebar مینشیند. سه ویژگی کلیدی:
- تودرتویی چندسطحی —
NavItemکهNavItemهای دیگر را بهعنوان children دارد، خودکار به parent قابلجمعشدن تبدیل میشود؛ depth بدون محدودیت. - کاسکید حالت فعال — وقتی
activePathبا یک leaf تودرتو match میکند، همهی parentها بهطور خودکارexpandمیشوند وdata-active-withinمیگیرند (highlight ملایمتر از leaf فعال). - گروههای قابلجمعشدن —
NavGroupباheadingقابلکلیک؛ کل گروه را باز/بسته میکند (بر خلاف سایدبار primitive که گروههایش static بودند).
چه زمانی استفاده کنیم:
- داشبوردهای enterprise با ناوبری ۳+ سطح (رصد → منابع → تلویزیون)
- اپهایی که کاربر باید یک نقطهی عمیق در درخت ناوبری را bookmark کند و هنگام بازگشت بهطور خودکار ببیند
- سایدبارهای طولانی که نیاز به group collapse دارند
چه زمانی استفاده نکنیم:
- ناوبری تخت با کمتر از ۸ آیتم — از
SidebarMenuprimitive استفاده کنید، سبکتر است - ناوبری افقی top-nav — از
NavigationMenuاستفاده کنید - ناوبری bottom-tab موبایل — از الگوی اختصاصی استفاده کنید (NavTree عمودی است)
زمین بازی
با تغییر تنظیمات زیر، پیشنمایش زنده را مشاهده کنید.
استفاده
'use client'
import { usePathname } from 'next/navigation'
import { Sidebar, SidebarContent, SidebarProvider, NavTree, NavTreeProvider, NavGroup, NavItem } from '@partodata/ui'
import { LayoutDashboard, BarChart3, Search, Settings } from 'lucide-react'
export function AppSidebar() {
const pathname = usePathname()
return (
<SidebarProvider>
<Sidebar>
<SidebarContent className="p-2">
<NavTreeProvider activePath={pathname}>
<NavTree>
<NavGroup heading="رصد و پایش">
<NavItem href="/" icon={LayoutDashboard}>
داشبورد
</NavItem>
<NavItem href="/clusters" icon={BarChart3}>
خوشهها
</NavItem>
<NavItem icon={Search}>
جستجو
<NavItem href="/search/posts">پستها</NavItem>
<NavItem href="/search/pages">صفحات</NavItem>
</NavItem>
</NavGroup>
<NavGroup heading="تنظیمات" defaultOpen={false}>
<NavItem href="/settings" icon={Settings}>
پیکربندی
</NavItem>
</NavGroup>
</NavTree>
</NavTreeProvider>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}کاسکید حالت فعال (خودکار)
وقتی activePath مطابق یک leaf تودرتو باشد، همهی parent های بالای آن بهطور خودکار data-active-within میگیرند و expand میشوند. دکمههای بالا را در دموی زیر تغییر دهید تا رفتار را ببینید:
جزئیات الگوریتم:
matchStrategy="prefix"(پیشفرض):/clustersهم برای/clustersو هم برای/clusters/42فعال میشود. فقط مرز segment رعایت میشود (یعنی/clبا/clustersmatch نمیشود).matchStrategy="exact": فقط تطابق دقیق.
گروههای قابلجمعشدن
headingنمایش یک ردیف سرگروه و بهطور پیشفرض قابلکلیک (collapse/expand)collapsible={false}heading را static میکند (مثل primitive SidebarGroupLabel)defaultOpen={false}برای بسته بودن در رندر اولopen+onOpenChangeبرای کنترل controlled
Props
NavTreeProvider
NavGroup
NavItem
NavSeparator
خط جداکنندهی افقی (<hr>) برای تفکیک بصری بخشهای ناوبری درون درخت. فقط ویژگیهای استاندارد <hr> را میپذیرد.
ادغام با Sidebar primitive
NavTree داخل SidebarContent (از primitive Sidebar) قرار میگیرد. SidebarProvider رفتار mobile/keyboard-shortcut را مدیریت میکند و NavTree ساختار ناوبری را.
<SidebarProvider>
<Sidebar variant="inset">
<SidebarHeader>...</SidebarHeader>
<SidebarContent className="p-2">
<NavTreeProvider activePath={pathname}>
<NavTree>...</NavTree>
</NavTreeProvider>
</SidebarContent>
<SidebarFooter>...</SidebarFooter>
</Sidebar>
</SidebarProvider>راهنمای استفاده
بکنید
- برای هر سطح nesting، یک آیکون بصری متمایز در NavItem بگذارید تا سلسلهمراتب بصری هم واضح باشد -
badgeرا برای شمارندهی notification یا new indicator استفاده کنید — از componentBadgeیا یک span سفارشی - در بخش تنظیمات (که معمولاً به ندرت باز میشود) ازNavGroup defaultOpen={false}استفاده کنید -matchStrategy="prefix"را حفظ کنید مگر اینکه routeهای overlap داشته باشید (مثلاً/clusterو/clusters)
نکنید
- بیش از ۴ سطح nesting نکنید — کاربر جنگل میبیند
- badge را برای متن طولانی (بیش از ۳ کاراکتر) استفاده نکنید — sidebar باریک میشود
- از
<NavItem>های داخل یک<div>ساده استفاده نکنید — split-children logic بر اساس React.Children مستقیم کار میکند - حالت
activeرا روی چند آیتم همزمان تنظیم نکنید — ممکن است highlight چندگانه گیجکننده شود
دسترسیپذیری
<nav aria-label="ناوبری اصلی">landmark برای screen reader- parent NavItem دارای
aria-expanded+ button semantics - کلیک، Space، و Enter همگی parent را toggle میکنند
- active leaf دارای
data-active="true"— بصری و برای automated testing - chevron بصری در RTL به شکل صحیح میچرخد (left → down در باز، rotate-90 در بسته)
محدودیتهای فعلی
- جستجو در درخت هنوز ارائه نشده. برنامهی بعدی:
NavSearchورودی که لیست را filter میکند و parent های مرتبط را باز نگه میدارد. (فاز ۱.۱ روادمپ — مرحلهی بعد) - Drag-reorder آیتمها در نظر نیست — این یک UI ناوبری است نه یک tree builder.
کامپوننتهای مرتبط
- Sidebar — container primitive که NavTree درون
SidebarContentقرار میگیرد - NavigationMenu — برای ناوبری افقی top-nav
- Breadcrumb — برای نمایش مسیر فعلی درون SiteHeader
- SiteHeader — هدر اپ که با NavTree جفت میشود