useDateRangePicker

Hook do wyboru zakresu dat z podwójnym kalendarzem miesięcznym, podglądem przy najechaniu myszką i predefiniowanymi zakresami.

Import

import { useDateRangePicker } from "react-date-range-picker-headless";

Użycie

import { useState } from "react";
import { useDateRangePicker } from "react-date-range-picker-headless";
function MyDateRangePicker() {
const [range, setRange] = useState<{ start: Date | null; end: Date | null }>({
start: null,
end: null,
});
const picker = useDateRangePicker({
value: range,
onChange: setRange,
presets: [
{
label: "Ostatnie 7 dni",
value: () => {
const end = new Date();
const start = new Date();
start.setDate(start.getDate() - 6);
return { start, end };
},
},
],
});
return (
<div ref={picker.containerRef}>
<button onClick={picker.handleToggle}>
{picker.displayValue || picker.locale.rangePlaceholder}
</button>
{picker.isOpen && (
<div ref={picker.popupRef} onKeyDown={picker.handleKeyDown}>
{/* Dwa kalendarze obok siebie */}
{[picker.leftCalendar, picker.rightCalendar].map((cal, calIdx) => (
<div key={calIdx}>
<span>{picker.locale.formatMonthYear(cal.month)}</span>
{cal.weeks.flat().map((day, i) => {
if (!day) return <span key={i} />;
const dp = picker.getDayProps(day, cal.month);
return (
<button
key={i}
onClick={() => picker.handleDateClick(day)}
onMouseEnter={() => picker.handleDateHover(day)}
onMouseLeave={() => picker.handleDateHover(null)}
>
{dp.day}
</button>
);
})}
</div>
))}
{/* Predefiniowane zakresy */}
{picker.presets.map((preset, i) => (
<button
key={i}
onClick={() => picker.handlePresetClick(preset)}
style={{ fontWeight: i === picker.activePresetIndex ? "bold" : "normal" }}
>
{preset.label}
</button>
))}
<button onClick={picker.handleConfirm}>{picker.locale.confirm}</button>
</div>
)}
</div>
);
}

Opcje

OpcjaTypDomyślnieOpis
value{ start: Date | null; end: Date | null }Wymagane. Aktualna wartość zakresu.
onChange(value: { start: Date | null; end: Date | null }) => voidWymagane. Wywoływane, gdy zakres się zmienia.
maxDaysnumberMaksymalna dozwolona liczba dni w zakresie (włącznie).
minDaysnumberMinimalna wymagana liczba dni w zakresie (włącznie).
presetsDateRangePreset[]Predefiniowane zakresy dat (np. “Ostatnie 7 dni”, “Ten miesiąc”).
allowSingleDateInRangebooleantrueGdy false, uniemożliwia wybór zakresu, w którym data początkowa jest równa końcowej.
minDateDateNajwcześniejsza data do wyboru.
maxDateDateNajpóźniejsza data do wyboru.
localePartial<Locale>DEFAULT_LOCALEZastępuje ciągi znaków lokalizacji.
initialMonthDatePoczątkowy miesiąc do wyświetlenia.
sizeDatePickerSizePrzekazywane do UI.
weekStartsOnWeekDay"sunday"Pierwszy dzień tygodnia.
isDateUnavailable(date: Date) => booleanNiestandardowa funkcja do wyłączania określonych dat.
displayFormatstringNiestandardowy ciąg formatujący dla wyświetlanej wartości.
openbooleanKontrolowany stan otwarcia.
initialOpenbooleanfalsePoczątkowy stan otwarcia (niekontrolowany).
onOpenChange(open: boolean) => voidFunkcja zwrotna wywoływana przy zmianie stanu otwarcia.
requiredbooleanfalseGdy true, handleClear nie wykonuje żadnej operacji.
todayDatenew Date()Zastępuje dzisiejszą datę.
onMonthChange(month: Date) => voidFunkcja zwrotna wywoływana przy zmianie wyświetlanego miesiąca.
disablePastbooleanfalseWyłącza wszystkie daty przed dzisiejszym dniem.
disableFuturebooleanfalseWyłącza wszystkie daty po dzisiejszym dniu.
showOutsideDaysbooleanfalsePokazuje dni z sąsiednich miesięcy.
highlightDatesDate[]Tablica dat do podświetlenia.
shouldCloseOnSelectbooleanfalseAutomatycznie potwierdza wybór po wybraniu daty końcowej.
numberOfMonthsnumber2Liczba miesięcy kalendarza do wyświetlenia.
captionLayoutCaptionLayout"buttons"Tryb układu nagłówka.
fromYearnumberbieżący rok - 100Rok początkowy dla listy rozwijanej.
toYearnumberbieżący rok + 10Rok końcowy dla listy rozwijanej.

Zwracane wartości

NazwaTypOpis
isOpenbooleanCzy wyskakujące okienko jest otwarte.
tempStartDateDate | nullTymczasowa data początkowa (przed potwierdzeniem).
tempEndDateDate | nullTymczasowa data końcowa (przed potwierdzeniem).
hoveredDateDate | nullAktualnie najechana data (dla podglądu zakresu).
leftMonthDateWyświetlany miesiąc lewego kalendarza.
rightMonthDateWyświetlany miesiąc prawego kalendarza.
localeLocaleRozwiązany obiekt lokalizacji.
leftCalendarCalendarMonthDane kalendarza dla lewego panelu.
rightCalendarCalendarMonthDane kalendarza dla prawego panelu.
calendarsCalendarMonth[]Tablica wszystkich miesięcy kalendarza.
getDayProps(date: Date, referenceMonth?: Date) => DayPropsOblicza flagi dla komórki dnia kalendarza. Przekaż referenceMonth, aby wykrywanie dni spoza miesiąca działało poprawnie w układach wielomiesięcznych.
displayValuestringSformatowany ciąg znaków potwierdzonego zakresu.
hasValuebooleanCzy zakres jest aktualnie potwierdzony.
canConfirmbooleanCzy bieżący wybór jest prawidłowy do potwierdzenia.
handleDateClick(date: Date) => voidObsługuje kliknięcie komórki dnia. Pierwsze kliknięcie ustawia początek, drugie koniec.
handleDateHover(date: Date | null) => voidObsługuje najechanie myszą w celu podglądu zakresu.
handlePrevMonth() => voidPrzewija oba kalendarze o jeden miesiąc do tyłu.
handleNextMonth() => voidPrzewija oba kalendarze o jeden miesiąc do przodu.
handleOpen() => voidOtwiera wyskakujące okienko.
handleClose() => voidZamyka wyskakujące okienko.
handleToggle() => voidPrzełącza wyskakujące okienko.
handleConfirm() => voidPotwierdza wybór i zamyka.
handleCancel() => voidAnuluje i przywraca poprzednią wartość.
handleClear() => voidCzyści zakres (nie wykonuje operacji, jeśli required).
handleGoToToday() => voidPrzechodzi do miesiąca z dzisiejszą datą.
containerRefRefObject<HTMLDivElement | null>Dołącz do elementu otaczającego w celu wykrywania kliknięć na zewnątrz.
popupRefRefObject<HTMLDivElement | null>Dołącz do elementu wyskakującego okienka.
focusedDateDate | nullData fokusowana za pomocą klawiatury.
handleKeyDown(e: KeyboardEvent<HTMLElement>) => voidHandler nawigacji za pomocą klawiatury.
presetsDateRangePreset[]Tablica predefiniowanych zakresów (przekazywana do renderowania).
handlePresetClick(preset: DateRangePreset) => voidZastosuj predefiniowany zakres.
activePresetIndexnumberIndeks aktualnie pasującego predefiniowanego zakresu (-1, jeśli brak).
yearsnumber[]Tablica lat dla trybu z listą rozwijaną.
monthsnumber[]Indeksy miesięcy dla trybu z listą rozwijaną.
handleYearSelect(year: number, calendarIndex?: number) => voidUstawia wyświetlany rok.
handleMonthSelect(month: number, calendarIndex?: number) => voidUstawia wyświetlany miesiąc.

Kluczowe zachowania

Proces wyboru zakresu

  1. Pierwsze kliknięcie ustawia datę początkową (data końcowa jest czyszczona)
  2. Drugie kliknięcie ustawia datę końcową (automatycznie zamienia się miejscami, jeśli jest wcześniejsza niż data początkowa)
  3. Trzecie kliknięcie resetuje i rozpoczyna nowy zakres

Podgląd przy najechaniu

Gdy użytkownik wybrał datę początkową, ale jeszcze nie końcową, handleDateHover aktualizuje hoveredDate. Funkcja getDayProps używa tej informacji do obliczenia isInHoverRange i isHoverTarget, co pozwala na wyświetlenie podglądu potencjalnego zakresu.

Predefiniowane zakresy

Predefiniowane zakresy mogą być statycznymi obiektami lub funkcjami fabrykującymi:

const presets = [
{ label: "Dzisiaj", value: { start: new Date(), end: new Date() } },
{
label: "Ostatnie 30 dni",
value: () => {
const end = new Date();
const start = new Date();
start.setDate(start.getDate() - 29);
return { start, end };
},
},
];

activePresetIndex zwraca indeks predefiniowanego zakresu, który pasuje do bieżącego wyboru, lub -1, jeśli żaden nie pasuje.

maxDays / minDays

Gdy ustawione jest maxDays, daty wykraczające poza dozwolony zakres od daty początkowej są automatycznie wyłączane. Gdy ustawione jest minDays, daty zbyt bliskie dacie początkowej są wyłączane.

shouldCloseOnSelect

W przypadku wyboru zakresu dat, shouldCloseOnSelect uruchamia automatyczne potwierdzenie po wybraniu daty końcowej (a nie daty początkowej).