انتخابگر تاریخ (DatePicker)

کامپوننت انتخاب بازه تاریخ با پشتیبانی از تقویم شمسی و میلادی

معرفی

کامپوننت Date Picker برای انتخاب بازه تاریخ (از تاریخ شروع تا تاریخ پایان) استفاده می‌شود. این کامپوننت از تقویم شمسی (جلالی) و میلادی پشتیبانی می‌کند و به طور کامل RTL است.

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

  • برای هر بازهٔ زمانی (از … تا) — از DateRangePicker با بازه‌های آماده‌اش استفاده کنید. حالت بازهٔ DatePicker (mode="range"، که هنوز پیش‌فرض است) منسوخ است و قاعدهٔ ESLint parto/date-range-control آن را گزارش می‌کند؛ mode="single" بنویسید
  • وقتی فقط ماه یا سال لازم دارید — از Select استفاده کنید

زمین بازی

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

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

استفاده پایه

import { DatePicker } from '@partodata/ui'
import { useState } from 'react'
import { DateRange } from 'react-day-picker'

export default function MyComponent() {
  const [dateRange, setDateRange] = useState<DateRange | undefined>()

  return <DatePicker value={dateRange} onChange={setDateRange} placeholder="انتخاب بازه تاریخ" />
}

تقویم شمسی (پیش‌فرض)

از نسخهٔ 4.0 تقویم پیش‌فرض شمسی است، مگر اینکه locale برابر en یا ar باشد (پیش از آن پیش‌فرض همیشه میلادی بود). برای تقویم میلادی usePersianCalendar={false} بدهید؛ مقدار صریح usePersianCalendar همیشه بر locale مقدم است. DateTimePicker و Calendar هنوز به‌طور پیش‌فرض میلادی‌اند.

// تقویم شمسی (پیش‌فرض)
;<DatePicker value={dateRange} onChange={setDateRange} placeholder="انتخاب بازه تاریخ" />

// تقویم میلادی
;<DatePicker value={dateRange} onChange={setDateRange} usePersianCalendar={false} />

برچسب دکمه همان برچسب DateRangePicker است: «25 - 30 دی 1402» برای بازه و «25 دی 1402» برای یک روز. ارقام با حروف لاتین در DOM نوشته می‌شوند و فونت آن‌ها را با قابلیت ss01 فارسی نشان می‌دهد، تا کپی، جست‌وجو و صفحه‌خوان درست کار کنند. تا 3٫x برچسب شمسی به شکل «1402/10/25» و با کد ارقام فارسی نوشته می‌شد.

اندازه و عرض

دکمهٔ باز کننده روی همان نردبان اندازهٔ کنترل‌ها (xs تا xl) قرار دارد؛ پیش‌فرض md (38 پیکسل) است، اندازهٔ فیلد فرم، و در نوار ابزار، FilterBar و سرِ کارت‌ها و سربرگ‌ها ردیف آن را sm (30 پیکسل) می‌کند. به‌طور پیش‌فرض دکمه تمام عرض ظرفش را با حداقل 220 پیکسل پر می‌کند؛ در نوار ابزار و ردیف فیلتر با autoWidth عرض آن به اندازهٔ متنش می‌شود:

<DatePicker size="xs" autoWidth value={dateRange} onChange={setDateRange} />

انتخاب یک تاریخ (بدون بازه)

برای انتخاب فقط یک تاریخ (نه بازه تاریخی)، باید mode را 'single' قرار دهید:

const [date, setDate] = useState<DateRange | undefined>()

;<DatePicker
  value={date}
  onChange={setDate}
  placeholder="انتخاب تاریخ"
  usePersianCalendar={true}
  mode="single"
  numberOfMonths={1}
/>

نکته: برای دریافت تاریخ انتخاب شده از date?.from استفاده کنید.

// دریافت تاریخ انتخاب شده
const selectedDate = date?.from
console.log(selectedDate) // Date object یا undefined

تعداد ماه‌ها

می‌توانید تعداد ماه‌های نمایش داده شده را تغییر دهید:

<DatePicker value={dateRange} onChange={setDateRange} numberOfMonths={1} />

بازه‌های پیش‌فرض (Presets)

با فعال کردن showPresets، دکمه‌های بازه‌های پیش‌فرض نمایش داده می‌شود:

تقویم شمسی با Presets

<DatePicker value={dateRange} onChange={setDateRange} showPresets={true} usePersianCalendar={true} />

تقویم میلادی با Presets

<DatePicker value={dateRange} onChange={setDateRange} showPresets={true} usePersianCalendar={false} />

بازه‌های پیش‌فرض همان بازه‌های آمادهٔ DateRangePicker است (DEFAULT_DATE_RANGE_PRESETS):

  • 7 روز اخیر / Last 7 days
  • 14 روز اخیر / Last 14 days
  • ماه گذشته (30 روز) / Last 30 days
  • 3 ماه گذشته / Last 3 months
  • 6 ماه گذشته / Last 6 months
  • 1 سال اخیر / Last year

زبان این برچسب‌ها از locale تعیین می‌شود (نه از usePersianCalendar) — یعنی <DatePicker locale="fa" usePersianCalendar={false} showPresets /> روی تقویم میلادی هم برچسب‌های فارسی نشان می‌دهد، و locale="ar" برچسب‌های عربی می‌دهد. locale را روی خود DatePicker تکرار نکنید: اگر تنظیم نشود، زبان صفحه است (locale قاب محصول یا قالب صفحه، که یک بار روی قاب داده می‌شود). فقط بیرون از قاب و قالب از تقویم تشخیص داده می‌شود («fa» برای تقویم شمسی که پیش‌فرض است، «en» با usePersianCalendar={false}).

جایگزین کردن بازه‌های پیش‌فرض

برای دوره‌های اختصاصی به‌جای شش گزینه‌ی پیش‌فرض، آرایه‌ی خودتان را به presets بدهید:

import { subDays } from 'date-fns'

const today = new Date()

;<DatePicker
  showPresets
  presets={[
    { label: 'سه روز اخیر', range: { from: subDays(today, 2), to: today } },
    { label: 'امسال', range: { from: new Date(today.getFullYear(), 0, 1), to: today } },
  ]}
/>

محدودیت تاریخ

می‌توانید حداقل و حداکثر تاریخ قابل انتخاب را مشخص کنید:

<DatePicker value={dateRange} onChange={setDateRange} minDate={new Date(2024, 0, 1)} maxDate={new Date(2024, 11, 31)} />

روزهای خارج از این بازه غیرفعال می‌شوند (قابل کلیک نیستند و onChange را صدا نمی‌زنند) و حرکت بین ماه‌ها هم به همین بازه محدود می‌شود — همان مکانیزم disabled/startMonth/endMonth که DateRangePicker استفاده می‌کند.

غیرفعال کردن

<DatePicker value={dateRange} onChange={setDateRange} disabled={true} />

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

بکنید

  • از DatePicker برای انتخاب یک تاریخ مشخص یا بازه تاریخی در فرم‌ها استفاده کنید - تقویم شمسی پیش‌فرض است؛ فقط برای محصول میلادی usePersianCalendar={false} بدهید - از showPresets برای بازه‌های رایج (7 روز اخیر، ماه گذشته) استفاده کنید تا انتخاب سریع‌تر شود - در ردیف فیلتر size را با کنترل‌های کناری یکی کنید و autoWidth بدهید

نکنید

  • وقتی فقط نیاز به انتخاب دوره‌های از پیش تعریف‌شده دارید (مانند 7 روز، 30 روز) از DatePicker استفاده نکنید — از PeriodSelector استفاده کنید - بدون تنظیم placeholder مناسب از DatePicker استفاده نکنید - فراموش نکنید که مقادیر Date همیشه میلادی هستند، حتی وقتی تقویم شمسی فعال است

Props

Prop

Type

نکات مهم

نوع DateRange

نوع DateRange از کتابخانه react-day-picker می‌آید:

import { DateRange } from 'react-day-picker'

type DateRange = {
  from: Date | undefined
  to: Date | undefined
}

تقویم شمسی

هنگام استفاده از usePersianCalendar={true}:

  • ✅ نمایش ماه‌های شمسی (فروردین، اردیبهشت، ...)
  • ✅ نمایش اعداد فارسی (1، 2، 3، ...)
  • ✅ نمایش روزهای هفته به فارسی (ش، ی، د، ...)
  • ✅ سال شمسی در عنوان
  • ⚠️ مقادیر Date همچنان میلادی هستند (فقط نمایش شمسی است)

انتخاب یک تاریخ

برای انتخاب یک تاریخ به جای بازه تاریخی:

  1. مقدار mode را 'single' قرار دهید (ضروری)
  2. توصیه می‌شود numberOfMonths را 1 قرار دهید
  3. از value?.from برای دسترسی به تاریخ انتخاب شده استفاده کنید
  4. در حالت single، دکمه‌های preset نمایش داده نمی‌شوند

مثال‌های کاربردی

فیلتر گزارش

const [reportRange, setReportRange] = useState<DateRange>()

;<DatePicker value={reportRange} onChange={setReportRange} placeholder="بازه گزارش" usePersianCalendar={true} />

رزرو هتل

const [checkInOut, setCheckInOut] = useState<DateRange>()

;<DatePicker value={checkInOut} onChange={setCheckInOut} placeholder="تاریخ ورود و خروج" numberOfMonths={2} />

با فرم

در یک فیلد فرم، DatePicker داخل FormRow است و به field در react-hook-form همان‌طور وصل می‌شود که جدول «کنترل هر نوع فیلد» می‌گوید: یک تاریخ با mode="single" (مقدار فیلد یک Date است)، و یک بازه با حالت پیش‌فرض (مقدار فیلد { from, to } است).

import { useForm } from 'react-hook-form'
import { DatePicker } from '@partodata/ui'
import { Form, FormField } from '@partodata/ui/form'
import { FormRow } from '@partodata/ui/templates'

type ReportValues = {
  start: Date | undefined
  period: { from: Date | undefined; to?: Date } | undefined
}

function ReportForm() {
  const form = useForm<ReportValues>()

  return (
    <Form {...form}>
      <FormField
        control={form.control}
        name="start"
        rules={{ required: 'تاریخ شروع را انتخاب کنید' }}
        render={({ field, fieldState }) => (
          <FormRow label="تاریخ شروع" required error={fieldState.error?.message}>
            <DatePicker
              mode="single"
              value={field.value ? { from: field.value } : undefined}
              onChange={(range) => field.onChange(range?.from)}
            />
          </FormRow>
        )}
      />
      <FormField
        control={form.control}
        name="period"
        render={({ field }) => (
          <FormRow label="بازهٔ گزارش">
            <DatePicker value={field.value} onChange={field.onChange} />
          </FormRow>
        )}
      />
    </Form>
  )
}

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

  • Calendar: کامپوننت داخلی که برای نمایش تقویم استفاده می‌شود
  • Popover: برای نمایش تقویم در یک پاپاور
  • Button: برای دکمه باز کردن تقویم
  • DateRangePicker: کامپوننت مشابه با امکانات بیشتر

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

  • دکمه trigger یک <button> استاندارد است؛ با Enter/Space باز می‌شود و popover تقویم فوکس را به‌صورت Radix Popover trap می‌کند.
  • در تقویم: کلیدهای جهت (← → ↑ ↓) برای جابه‌جایی روز، Page Up/Page Down برای ماه، و Home/End برای ابتدا/انتهای هفته کار می‌کنند.
  • Enter تاریخ زیر فوکس را انتخاب می‌کند؛ در mode="range" پس از انتخاب از/تا popover خودکار بسته می‌شود.
  • Escape popover را بدون اعمال تغییر می‌بندد و فوکس به دکمه trigger برمی‌گردد.
  • preset buttons (وقتی showPresets={true} است) عناصر button استاندارد با focus ring هستند — با Tab قابل دسترس و با Enter قابل فعال‌سازی.
  • روزهای انتخاب‌شده aria-selected="true" و روزهای غیرفعال (خارج از minDate/maxDate) aria-disabled="true" هستند — screen reader وضعیت را اعلام می‌کند.
  • در حالت usePersianCalendar={true}، نام ماه/روز و اعداد به فارسی اعلام می‌شوند ولی مقدار Date همچنان میلادی باقی می‌ماند — بنابراین value معنادار است.

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

  • DateRangePicker — اگر نیاز به انتخاب بازه تاریخی با label و امکانات بیشتر دارید، از DateRangePicker استفاده کنید
  • PeriodSelector — اگر کاربر فقط از بین دوره‌های از پیش تعریف‌شده انتخاب می‌کند (7 روز، 30 روز)، PeriodSelector ساده‌تر است
  • Calendar — اگر نیاز به نمایش تقویم بدون input field و popover دارید، از Calendar مستقیماً استفاده کنید