درخت ناوبری (NavTree)
لایهی ناوبری تودرتو با گروههای قابلجمعشدن، کاسکید حالت فعال، و indent خودکار — برای درختهای عمیق درون یک ابزار؛ منوی اصلی برنامه ProductFrame است
منوی اصلی برنامه نیست
منوی اصلی هر محصول را ProductFrame از روی داده میسازد (گروهها و یک سطح
زیرمجموعه)، یک بار در layout ریشه. NavTree برای درختی عمیق درون یک ابزار یا صفحه است (مثلاً درخت منابع یک ابزار
رصد)؛ قاب برنامه را با NavTree نسازید.
معرفی
NavTree درخت ناوبری درون یک ابزار است. سه ویژگی کلیدی:
- تودرتویی چندسطحی —
NavItemکهNavItemهای دیگر را بهعنوان children دارد، خودکار به parent قابلجمعشدن تبدیل میشود؛ depth بدون محدودیت. - کاسکید حالت فعال — وقتی
activePathبا یک leaf تودرتو match میکند، همهی parentها بهطور خودکارexpandمیشوند وdata-active-withinمیگیرند (highlight ملایمتر از leaf فعال). - گروههای قابلجمعشدن —
NavGroupباheadingقابلکلیک؛ کل گروه را باز/بسته میکند .
چه زمانی استفاده کنیم:
- درخت عمیق (3+ سطح) درون یک ابزار، مثل درخت منابع رصد (رصد → منابع → تلویزیون)
- ابزاری که کاربر باید یک نقطهی عمیق در درخت را bookmark کند و هنگام بازگشت بهطور خودکار ببیند
- پنلهای کناری طولانی درون ابزار که نیاز به group collapse دارند
چه زمانی استفاده نکنیم:
- منوی اصلی برنامه →
ProductFrame - ناوبری تخت با کمتر از 8 آیتم —
TabsیاSecondaryNav - ناوبری اصلی برنامه — از
ProductFrame(نوار ناوبری و ناوبری دوم) استفاده کنید - ناوبری bottom-tab موبایل — از الگوی اختصاصی استفاده کنید (NavTree عمودی است)
تلویزیون › خبری
منشنها و پوشش این منبع در هفتهٔ گذشته.
زمین بازی
با تغییر تنظیمات زیر، پیشنمایش زنده را مشاهده کنید.
استفاده
'use client'
import { usePathname } from 'next/navigation'
import { NavTree, NavTreeProvider, NavGroup, NavItem } from '@partodata/ui'
import { Newspaper, Radio, Tv } from 'lucide-react'
// Inside the sources page of a monitoring tool: its own deep tree, next to the page content. The product's main
// menu is ProductFrame's. The tree stays in the page's flow (not fixed to the viewport over the frame's menu).
// `aria-label`: the tree is named after what it navigates.
export function SourcesTree() {
const pathname = usePathname()
return (
<div className="rounded-lg border p-2">
<NavTreeProvider activePath={pathname}>
<NavTree aria-label="منابع">
<NavGroup heading="منابع رسانهای">
<NavItem href="/sources/press" icon={Newspaper}>
مطبوعات
</NavItem>
<NavItem icon={Tv}>
تلویزیون
<NavItem href="/sources/tv/news">خبری</NavItem>
<NavItem href="/sources/tv/sports">ورزشی</NavItem>
</NavItem>
</NavGroup>
<NavGroup heading="صوتی" defaultOpen={false}>
<NavItem href="/sources/radio" icon={Radio}>
رادیو
</NavItem>
</NavGroup>
</NavTree>
</NavTreeProvider>
</div>
)
}کاسکید حالت فعال (خودکار)
وقتی 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 میکندdefaultOpen={false}برای بسته بودن در رندر اولopen+onOpenChangeبرای کنترل controlled
Props
NavTreeProvider
NavGroup
NavItem
NavSeparator
خط جداکنندهی افقی (<hr>) برای تفکیک بصری بخشهای ناوبری درون درخت. فقط ویژگیهای استاندارد <hr> را میپذیرد.
درون یک صفحه
NavTree ستونی از خود صفحه است که روی موبایل بالای محتوا و از md کنار آن مینشیند؛ <main> دوم و نوار چسبیده به
viewport ندارد (زیر منوی قاب پنهان میشود). عنوان و پانویس درخت، عناصر خود صفحهاند.
<div className="flex flex-col rounded-lg border md:flex-row">
<div className="w-full border-b p-2 md:w-64 md:border-e md:border-b-0">
<NavTreeProvider activePath={pathname}>
<NavTree aria-label="منابع">...</NavTree>
</NavTreeProvider>
</div>
<div className="min-w-0 flex-1 p-4">{/* محتوای منبع انتخابشده */}</div>
</div>راهنمای استفاده
بکنید
- هر
NavTreeرا باaria-labelبه نام چیزی که پیمایش میکند بنامید (مثلاً «منابع») - برای هر سطح nesting، یک آیکون بصری متمایز در NavItem بگذارید تا سلسلهمراتب بصری هم واضح باشد
badgeرا برای شمارندهی notification یا new indicator استفاده کنید — از componentBadgeیا یک span سفارشی- در بخش تنظیمات (که معمولاً به ندرت باز میشود) از
NavGroup defaultOpen={false}استفاده کنید matchStrategy="prefix"را حفظ کنید مگر اینکه routeهای overlap داشته باشید (مثلاً/clusterو/clusters)- اگر بخش خودش هم یک صفحهی مقصد دارد (مثلاً «تحلیل» که هم قابلناوبری است و هم زیرمنو دارد)، روی parent هم
hrefبگذارید — بهطور کامل قابلناوبری میشود و toggle زیرمنو جدا از آن کار میکند
نکنید
- منوی اصلی برنامه را با
NavTreeنسازید — منوی اصلیnavدرProductFrameاست - بیش از 4 سطح nesting نکنید — کاربر جنگل میبیند
- badge را برای متن طولانی (بیش از 3 کاراکتر) استفاده نکنید — sidebar باریک میشود
- از
<NavItem>های داخل یک<div>ساده استفاده نکنید — split-children logic بر اساس React.Children مستقیم کار میکند - حالت
activeرا روی چند آیتم همزمان تنظیم نکنید — ممکن است highlight چندگانه گیجکننده شود
دسترسیپذیری
NavTreeیک لندمارک<nav>است؛ باaria-label(یاaria-labelledby) آن را به نام چیزی که پیمایش میکند بنامید، مثلaria-label="منابع". بدون نام، درون صفحهٔProductFrame«ناوبری صفحه» نام میگیرد (نام «ناوبری اصلی» مال منوی قاب است و دو لندمارک همنام نمیسازد) و بیرون از آن «ناوبری اصلی»- parent NavItem بدون
href/onClick(صرفاً اطلاعرسانی): کل ردیف یک دکمه است باaria-expanded؛ کلیک، Space و Enter آن را toggle میکنند - parent NavItem با
hrefیاonClick(یعنی خودش هم مقصد ناوبری/عمل است): ردیف به دو المان مجزا تقسیم میشود — برچسب اصلی (<a>/<button>واقعی که ناوبری میکند) و یک دکمهٔ کوچک جداگانه باaria-expandedبرای باز/بستهکردن زیرمنو؛ چون دو المان تعاملی نمیتوانند تودرتو باشند - active leaf دارای
data-active="true"— بصری و برای automated testing - chevron بصری در RTL به شکل صحیح میچرخد (left → down در باز، rotate-90 در بسته)
محدودیتهای فعلی
- جستجو در درخت هنوز ارائه نشده. برنامهی بعدی:
NavSearchورودی که لیست را filter میکند و parent های مرتبط را باز نگه میدارد. (فاز 1.1 روادمپ — مرحلهی بعد) - Drag-reorder آیتمها در نظر نیست — این یک UI ناوبری است نه یک tree builder.
کامپوننتهای مرتبط
- قاب محصول (ProductFrame) — منوی اصلی برنامه (
nav، باchildrenبرای پیوندهای هر بخش) - ProductFrame — قاب برنامه با ناوبری اصلی
- PageHeader — مسیر فعلی صفحه (breadcrumb) در
breadcrumbsسربرگ صفحه