پرتوپرتو

نوار پیشرفت ناوبری (RouteProgress)

نوار گرادیانی نازک بالای صفحه برای نمایش transition روت یا job های بلند — با trickle خودکار

معرفی

RouteProgress یک نوار گرادیانی ۲px که روی لبه‌ی بالای صفحه شناور است. سه حالت استفاده: (۱) controlled با active prop، (۲) imperative با start() / finish() روی ref، (۳) fully controlled با مقدار عددی value در [0, 1].

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

  • هنگام transition روت در Next.js (router.events.on('routeChangeStart'...)) — به کاربر feedback لحظه‌ای می‌دهد
  • برای upload فایل یا job بلند (مقدار مشخص)
  • برای هر عملیات async که UI را بلاک نمی‌کند اما کاربر باید بداند در حال اجراست

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

  • برای loading state کامپوننت خاص — از Skeleton یا ChartLoadingSkeleton استفاده کنید
  • برای progress بلند‌مدت با مقدار مشخص درون کارت/فرم — از Progress معمولی استفاده کنید
  • برای پیام‌های موفقیت/خطا — از Toast یا Banner استفاده کنید
نوار بالای این کادر را تماشا کنید — با کلیک روی دکمه‌ها حرکت می‌کند.

زمین بازی

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

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

سه حالت استفاده

حالت ۱: Controlled با active

const [isNavigating, setIsNavigating] = React.useState(false)

<RouteProgress active={isNavigating} />

مادامی که active={true} بار ترقه‌ای تا trickleCap (پیش‌فرض ۰.۹) جلو می‌رود. با active={false} snap به ۱۰۰٪ و fade out.

controlled: active prop — trickles while true، snaps to 100٪ هنگام false.

حالت ۲: Imperative با ref

const ref = React.useRef<RouteProgressHandle>(null)

router.events.on('routeChangeStart', () => ref.current?.start())
router.events.on('routeChangeComplete', () => ref.current?.finish())

<RouteProgress ref={ref} />

حالت ۳: Fully controlled (مقدار)

const progress = useUploadProgress() // 0..1 از upload

<RouteProgress value={progress} />

وقتی value دست‌دست شده، بار نه trickle نه fade می‌کند — دقیقاً همان‌جاست که گذاشتید.

ادغام با Next.js App Router

در Next.js 14+ که event loop router آن تغییر کرده، راحت‌ترین راه استفاده از useTransition در کنار useRouter:

'use client'
import { useRouter } from 'next/navigation'
import { useTransition } from 'react'
import { RouteProgress } from '@parto-system-design/ui'

export function NavLink({ href, children }) {
  const router = useRouter()
  const [pending, start] = useTransition()

  return (
    <>
      <RouteProgress active={pending} />
      <a
        onClick={(e) => {
          e.preventDefault()
          start(() => router.push(href))
        }}
      >
        {children}
      </a>
    </>
  )
}

Props

Prop

Type

RouteProgressHandle (ref)

type RouteProgressHandle = {
  start: () => void // reset + show + trickle
  finish: () => void // snap to 100% + fade out
}

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

بکنید

  • از active برای route transitionها استفاده کنید — API تمیزتر از ref است - trickleCap را کم نکنید — ۰.۹ حس انتظار طبیعی می‌دهد، ۰.۷ کاربر را می‌ترساند که «گیر کرده» - prefers-reduced-motion توسط browser بصورت خودکار احترام نهاده می‌شود — نوار همچنان کار می‌کند اما animation ساده‌تر

نکنید

  • active و value را هم‌زمان پاس ندهید — رفتار غیرقابل‌پیش‌بینی می‌شود - چند RouteProgress هم‌زمان در صفحه mount نکنید — فقط یک نوار گلوبال، در layout.tsx ریشه - نوار را برای loading صفحه‌ی کل استفاده نکنید وقتی UI زیرش بلاک است — از PageLoader استفاده کنید

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

  • role="progressbar" + aria-valuenow + aria-valuemin/max — assistive tech درصد را می‌خواند
  • pointer-events-none — روی کلیک‌پذیری المان‌های زیر تأثیر نمی‌گذارد
  • z-index بالاتر از tooltip — روی مودال‌ها هم پیداست (هدف: هشدار بصری transition)

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

  • Progress — برای progress درون‌صفحه‌ای (کارت، فرم)
  • Spinner — برای loading کوچک درون دکمه
  • PageLoader — برای blocking loading صفحه‌ی کامل
  • SiteHeader — معمولاً بالای هدر قرار می‌گیرد