پنل کناری (Sheet)

پنل کشویی از کنار صفحه

معرفی

کامپوننت Sheet یک پنل کشویی است که از کنار صفحه ظاهر می‌شود.

چه زمانی استفاده کنیم:

  • برای فرم‌های بلند (بیش از 5 فیلد) که در Dialog جا نمی‌شوند
  • برای پنل‌های جزئیات (detail panel) در کنار لیست اصلی
  • برای تنظیمات، فیلترهای پیشرفته، یا پنل‌های ویرایش در desktop

چه زمانی استفاده نکنیم:

  • برای محتوای کوچک مثل تأیید — از Dialog استفاده کنید
  • برای تأیید اعمال مخرب — از AlertDialog استفاده کنید
  • برای filter panel در موبایل — از Drawer استفاده کنید

زمین بازی

با تغییر تنظیمات زیر، پیش‌نمایش زنده را مشاهده کنید.

زمین بازی
تنظیمات
چیدمان
محتوا
import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, Button, SheetDescription } from '@partodata/ui'

<Sheet>
  <SheetTrigger asChild>
    <Button type="default" size="sm">باز کردن پنل</Button>
  </SheetTrigger>
  <SheetContent>
    <SheetHeader>
      <SheetTitle>عنوان پنل</SheetTitle>
      <SheetDescription>توضیحات پنل کناری.</SheetDescription>
    </SheetHeader>
  </SheetContent>
</Sheet>

استفاده

import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from '@partodata/ui'
import { Button } from '@partodata/ui'

export default function MyComponent() {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button>باز کردن</Button>
      </SheetTrigger>
      <SheetContent>
        <SheetHeader>
          <SheetTitle>عنوان</SheetTitle>
          <SheetDescription>توضیحات در اینجا قرار می‌گیرد</SheetDescription>
        </SheetHeader>
      </SheetContent>
    </Sheet>
  )
}

حالت‌ها و انواع

پیش‌فرض

جهت‌های مختلف

Sheet از چهار جهت باز شدن پشتیبانی می‌کند: end (پیش‌فرض)، start، top و bottom.

مقادیر start و end منطقی (logical) هستند و با جهت صفحه می‌چرخند: end یعنی لبهٔ پایانیِ خط خواندن — در RTL سمت چپ و در LTR سمت راست. top و bottom فیزیکی‌اند و تغییر نمی‌کنند.

<Sheet>
  <SheetTrigger asChild>
    <Button variant="outline">از بالا</Button>
  </SheetTrigger>
  <SheetContent side="top">
    <SheetHeader>
      <SheetTitle>عنوان</SheetTitle>
    </SheetHeader>
  </SheetContent>
</Sheet>

حالت بخش‌بندی‌شده (sectioned)

با sectioned روی SheetContent، سربرگ و فوتر خط‌دار می‌شوند و بدنه در یک SheetBody اسکرول‌شونده قرار می‌گیرد — مناسب فرم‌های چندبخشی و پنل‌های تنظیمات طولانی.

import {
  Sheet,
  SheetTrigger,
  SheetContent,
  SheetHeader,
  SheetTitle,
  SheetBody,
  SheetFooter,
  Button,
} from '@partodata/ui'
;<Sheet>
  <SheetTrigger asChild>
    <Button>ویرایش کمپین</Button>
  </SheetTrigger>
  <SheetContent sectioned>
    <SheetHeader>
      <SheetTitle>ویرایش کمپین</SheetTitle>
    </SheetHeader>
    <SheetBody>{/* فیلدهای فرم */}</SheetBody>
    <SheetFooter>
      <Button variant="outline">انصراف</Button>
      <Button variant="primary">ذخیره</Button>
    </SheetFooter>
  </SheetContent>
</Sheet>

سمت‌های مختلف

<SheetContent side="end"> {/* پیش‌فرض — لبهٔ پایانی: چپ در RTL، راست در LTR */}
<SheetContent side="start"> {/* لبهٔ آغازین: راست در RTL، چپ در LTR */}
<SheetContent side="top">
<SheetContent side="bottom">

left و right در 5.0 حذف شدند

left و right تا 4.x نام‌های قدیمی start و end بودند (right دقیقاً end و left دقیقاً start، نه راست و چپ فیزیکی). از 5.0 فقط start/end پذیرفته می‌شوند.

راهنمای استفاده

بکنید

  • از side مناسب استفاده کنید — end برای پنل‌های جزئیات، start برای ناوبری - همیشه SheetTitle و SheetDescription را ارائه دهید - برای فرم‌های داخل Sheet، دکمه ذخیره را در پایین Sheet قرار دهید

نکنید

  • از Sheet در موبایل استفاده نکنید — از Drawer استفاده کنید - Sheet های تودرتو ایجاد نکنید - محتوای بسیار کوتاه (مثل یک پیام تأیید) را در Sheet قرار ندهید — از Dialog استفاده کنید

جدول ویژگی‌ها

Sheet

Prop

Type

SheetContent

Prop

Type

رفتار در RTL

پراپ side در این کامپوننت به صورت منطقی (logical) عمل می‌کند، نه فیزیکی:

  • side="end" (پیش‌فرض) سمت «انتها»ی خط خواندن است:

    • در چیدمان RTL: سمت چپ صفحه
    • در چیدمان LTR: سمت راست صفحه
  • side="start" سمت «ابتدا»ی خط خواندن است:

    • در چیدمان RTL: سمت راست صفحه
    • در چیدمان LTR: سمت چپ صفحه
  • side="top" و side="bottom" فیزیکی هستند و با تغییر جهت صفحه تغییر نمی‌کنند.

قاعدهٔ سمت: جزئیات و فیلترها همیشه از end باز می‌شوند (پیش‌فرض؛ در RTL از چپ): EntityDrawer، پنل جزئیات URL، جزئیات پست (Post با layout="details") و پنل فیلتر موبایل (FilterPanel داخل Sheet). ناوبری از start باز می‌شود (در RTL از راست): منوی موبایل ProductFrame و NavRail. فقط نام‌های منطقی را بنویسید.

  • نام‌های فیزیکی side="right" و side="left" در 5.0 حذف شدند؛ side="right" در RTL پنل را سمت چپ می‌آورد.

دسترسی‌پذیری

  • با Escape بسته می‌شود
  • focus trap برای پیمایش کیبورد
  • از role="dialog" و aria-modal استفاده می‌شود
  • اسکرول صفحه در هنگام باز بودن قفل می‌شود
  • هنگام بستن، Radix فوکوس را به SheetTrigger برمی‌گرداند. Sheetی که controlled است و SheetTrigger ندارد (از یک کارت، سطر جدول یا دکمه‌ی بیرونی با open باز می‌شود) باید خودش فوکوس را برگرداند؛ وگرنه فوکوس روی <body> می‌افتد و Tab بعدی از بالای صفحه شروع می‌شود. onOpenAutoFocus پیش از آنکه فوکوس وارد پنل شود صدا زده می‌شود، پس document.activeElement در آن هنوز همان عنصر بازکننده است:
const returnFocus = React.useRef<HTMLElement | null>(null)

<SheetContent
  onOpenAutoFocus={() => {
    returnFocus.current = document.activeElement as HTMLElement | null
  }}
  onCloseAutoFocus={(event) => {
    event.preventDefault()
    returnFocus.current?.focus()
  }}
>

EntityDrawer این کار را خودش انجام می‌دهد؛ WhatsNewPanel و NavRail در موبایل فوکوس را به triggerRef برمی‌گردانند.

تعامل با کیبورد

  • Escape: بستن شیت - Tab: حرکت بین عناصر داخل شیت (فوکوس محبوس) - Shift + Tab: حرکت معکوس فوکوس

کشوی پایین روی موبایل: Drawer

Drawer (کشیدنی با انگشت) فقط برای کشوی پایینِ صفحه‌های لمسی است (مرجع). برای هر پنل کناری Sheet را به کار ببرید؛ مقدارهای start و end در Drawer منسوخ‌اند.

کامپوننت‌های مرتبط

  • Drawer — وقتی در موبایل نیاز به پنل دارید (از پایین صفحه باز می‌شود)
  • Dialog — وقتی محتوا کوتاه است و نیاز به پنل کناری کامل ندارید
  • AlertDialog — برای هشدارهای اجباری که کاربر باید حتماً تأیید کند