پرتوپرتو

PostBulkActionBar (نوار اعمال گروهی)

نوار شناور پایین صفحه که با انتخاب چند پست در PostList ظاهر می‌شود — تگ، بولتن، خروجی، پرچم.

معرفی

<PostBulkActionBar> همان الگوی Gmail / Linear / Notion: وقتی یک یا چند پست انتخاب می‌شوند، یک نوار شناور رند در پایین viewport می‌چسبد و اکشن‌های گروهی را نمایش می‌دهد. به‌طور پیش‌فرض داخل <PostList> Auto-wired است و فقط وقتی onSelectedIdsChange تنظیم شده فعال می‌شود.

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

  • برای فیدهایی که نیاز به اعمال یک عمل روی چند پست دارند (تگ‌گذاری، خروجی، طبقه‌بندی sentiment).
  • وقتی کاربر در جریان triage باید تعداد موارد انتخاب‌شده را همیشه ببیند و بتواند با یک حرکت آن را پاک کند.
  • برای گردش‌کارهای حجیم — مانند برچسب‌گذاری یک‌جای پست‌های «کمپین تخفیف فصلی» یا خروجی گرفتن از بازخوردهای «رونمایی محصول جدید».

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

  • برای اکشن تک‌پستی — از <PostActions> روی خود کارت استفاده کنید.
  • وقتی هیچ عمل گروهی تعریف نشده و فقط می‌خواهید تعداد انتخاب را نمایش دهید — یک Badge یا متن ساده کافی است.
  • برای اکشن‌های ثابت صفحه که به انتخاب وابسته نیستند — این نوار فقط با selectedCount > 0 رندر می‌شود و جای toolbar دائمی را نمی‌گیرد.

زمین بازی

زمین بازی
تنظیمات
داده
3
کد این نمونه به‌صورت خودکار قابل تولید نیست — برای کد آماده‌ی copy/paste به بخش «استفاده» در بالای صفحه مراجعه کنید.

استفاده

به‌طور خودکار توسط <PostList> رندر می‌شود وقتی onSelectedIdsChange ست شده. برای استفاده‌ی مستقل:

import { PostBulkActionBar } from '@partodata/ui'
;<PostBulkActionBar
  selectedCount={selectedIds.length}
  selectedIds={selectedIds}
  onClear={() => setSelectedIds([])}
  actions={[
    { id: 'tag', label: 'تگ', icon: Tag, onClick: (ids) => bulkTag(ids) },
    {
      id: 'export',
      label: 'خروجی',
      icon: Download,
      options: [
        { id: 'csv', label: 'CSV' },
        { id: 'json', label: 'JSON' },
      ],
      onClick: (ids, opt) => exportAs(ids, opt),
    },
  ]}
/>

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

بکنید

  • onClear را همیشه تنظیم کنید — دکمه ضربدر و میان‌بر Esc فقط وقتی فعال می‌شوند که onClear داده شده باشد.
  • selectedCount را از selectedIds.length مشتق کنید تا شمارنده نوار و آرایه‌ای که به اکشن‌ها می‌رسد همیشه هم‌گام باشند.
  • برای اکشن‌های چندگزینه‌ای (مانند خروجی CSV / JSON / PDF) از options استفاده کنید — کامپوننت خودش DropdownMenu می‌سازد و گزینه انتخاب‌شده را به‌صورت optionId به onClick می‌دهد.
  • برای عمل مخرب گروهی (مانند پرچم‌گذاری) variant: 'danger' بدهید تا دکمه با استایل قرمز رندر شود.
  • اکشن‌هایی که در وضعیت فعلی بی‌معنا هستند را با hidden: true حذف و اکشن‌های موقتاً غیرمجاز را با disabled غیرفعال کنید — نه با unmount کردن کل نوار.

نکنید

  • بیش از چهار-پنج اکشن سطح‌اول در نوار قرار ندهید — نوار افقی است و روی صفحه‌های باریک سرریز می‌شود؛ اکشن‌های فرعی را در options گروه‌بندی کنید.
  • بیش از یک نمونه از نوار را هم‌زمان رندر نکنید — موقعیت آن fixed در وسط پایین viewport است و دو نمونه روی هم می‌افتند.
  • z-index آن را دستی بالا نبرید — لایه z-overlay عمداً زیر modal/popover می‌ماند تا دیالوگ‌های تأیید روی نوار باز شوند.
  • وقتی از <PostList> استفاده می‌کنید نوار را جداگانه رندر نکنید — با تنظیم onSelectedIdsChange به‌صورت خودکار wired می‌شود.
  • به اکشن‌های پیش‌فرض در محیط واقعی اتکا نکنید — onClick آن‌ها خالی است و فقط برای پیش‌نمایش/playground کاربرد دارند.

Props

PostBulkActionBar

Prop

Type

سایر ویژگی‌های HTMLAttributes<HTMLDivElement> (مانند className) به div ریشه منتقل می‌شوند؛ فقط onClick عمداً از تایپ حذف (Omit) شده است.

PostBulkAction

Prop

Type

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

  • ریشه نوار role="toolbar" با aria-label="اعمال گروهی روی پست‌های انتخاب‌شده" دارد — screen reader آن را به‌عنوان یک toolbar مستقل اعلام می‌کند.
  • دکمه ضربدر یک <button> واقعی با aria-label="پاک کردن انتخاب" و حلقه فوکوس مرئی (focus-visible:ring) است.
  • جداکننده عمودی بین شمارنده و اکشن‌ها aria-hidden="true" دارد و برای screen reader خوانده نمی‌شود.
  • وقتی selectedCount صفر شود کل نوار از DOM حذف می‌شود — هیچ عنصر focusable مخفی باقی نمی‌ماند.
  • انیمیشن slide-up با motion-reduce:animate-none برای کاربرانی که prefers-reduced-motion فعال دارند غیرفعال می‌شود.
  • شمارنده با رقم فارسی (convertToLocalNumbers) و کلاس tabular-nums رندر می‌شود. tabular-nums اینجا بی‌اثر است — فونت tnum ندارد — پس ارقام هم‌عرض نمی‌شوند؛ پایداری چیدمان از عرضِ ثابت ظرف می‌آید، نه از این کلاس.

کیبورد

  • Esc → پاک کردن انتخاب
  • listener کلید Esc سراسری (روی window) است — از هر جای صفحه کار می‌کند، نه فقط وقتی فوکوس روی نوار است؛ و فقط وقتی attach می‌شود که onClear تنظیم شده باشد.
  • Tab / Shift+Tab → حرکت بین دکمه ضربدر و دکمه‌های اکشن (هر کنترل یک tab-stop مستقل است؛ نوار roving tabindex ندارد).
  • Enter / Space → فعال‌سازی اکشن فوکوس‌شده؛ روی اکشن‌های دارای options منوی گزینه‌ها باز می‌شود.
  • در منوی باز، کلیدهای جهت‌دار بین گزینه‌ها حرکت می‌کنند و Enter گزینه را اجرا می‌کند (رفتار استاندارد DropdownMenu).

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

  • PostActions — برای اکشن‌های تک‌کارتی روی خود کارت؛ نوار گروهی فقط برای اعمال یک عمل روی چند پست هم‌زمان است.
  • PostList — برای کنترل selection state با selectedIds و onSelectedIdsChange؛ با تنظیم onSelectedIdsChange همین نوار به‌صورت خودکار رندر می‌شود.
  • DropdownMenu — اگر منوی گزینه‌ها را خارج از الگوی اکشن گروهی نیاز دارید؛ اکشن‌های دارای options به‌صورت داخلی از همین کامپوننت ساخته می‌شوند.
  • Badge — اگر فقط نمایش تعداد انتخاب بدون هیچ اکشن گروهی کافی است.