Özel Arayüz Oluşturma
Bu kılavuz, headless hook’lar üzerine kendi tarih seçici arayüzünüzü oluşturma modelini adım adım açıklamaktadır.
Model
Her headless hook aynı modeli izler:
- Hook’u çağırın seçeneklerinizle (
value,onChange, yapılandırma) - Dönüş değerini parçalayın
state, hesaplanmış değerler ve işleyicileri (handlers) almak için - Kendi işaretlemenizi oluşturun dönen değerleri kullanarak
- Etkileşimleri bağlayın sağlanan işleyicileri çağırarak
Hook, tüm karmaşıklığı yönetir — takvim oluşturma, tarih matematiği, açma/kapama durumu, klavye ile gezinme, aralık mantığı — ve siz yalnızca sunuma odaklanırsınız.
Örnek: Özel Tarih Seçici
import { useState } from "react";import { useDatePicker } from "react-date-range-picker-headless";
function CustomDatePicker() { const [value, setValue] = useState<Date | null>(null);
const { isOpen, calendar, getDayProps, displayValue, hasValue, canConfirm, locale, handleToggle, handleDateClick, handleConfirm, handleCancel, handleClear, handlePrevMonth, handleNextMonth, handleKeyDown, containerRef, popupRef, } = useDatePicker({ value, onChange: setValue });
return ( <div ref={containerRef} style={{ position: "relative", display: "inline-block" }}> {/* Trigger */} <button onClick={handleToggle} style={{ padding: "8px 16px", border: "1px solid #d1d5db", borderRadius: 6, background: "white", cursor: "pointer", minWidth: 180, textAlign: "left", }} > {displayValue || locale.placeholder} </button>
{/* Popup */} {isOpen && ( <div ref={popupRef} onKeyDown={handleKeyDown} style={{ position: "absolute", top: "100%", left: 0, marginTop: 4, padding: 16, background: "white", border: "1px solid #e5e7eb", borderRadius: 8, boxShadow: "0 4px 12px rgba(0,0,0,0.1)", zIndex: 50, }} > {/* Header */} <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 12, }} > <button onClick={handlePrevMonth}>{locale.prevMonth}</button> <span style={{ fontWeight: 600 }}>{locale.formatMonthYear(calendar.month)}</span> <button onClick={handleNextMonth}>{locale.nextMonth}</button> </div>
{/* Weekday headers */} <div style={{ display: "grid", gridTemplateColumns: "repeat(7, 36px)", gap: 2, textAlign: "center", }} > {locale.weekdays.map((wd) => ( <span key={wd} style={{ fontSize: 12, color: "#9ca3af", padding: 4 }}> {wd} </span> ))} </div>
{/* Calendar grid */} <div style={{ display: "grid", gridTemplateColumns: "repeat(7, 36px)", gap: 2 }}> {calendar.weeks.flat().map((day, i) => { if (!day) return <span key={i} />; const dp = getDayProps(day); return ( <button key={i} onClick={() => handleDateClick(day)} disabled={dp.isDisabled} style={{ width: 36, height: 36, borderRadius: "50%", border: dp.isFocused ? "2px solid #0ea5e9" : "none", background: dp.isSelected ? "#0ea5e9" : dp.isToday ? "#f0f9ff" : "transparent", color: dp.isSelected ? "white" : dp.isDisabled ? "#d1d5db" : "inherit", cursor: dp.isDisabled ? "not-allowed" : "pointer", fontWeight: dp.isToday ? 600 : 400, }} > {dp.day} </button> ); })} </div>
{/* Footer */} <div style={{ display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 12 }}> {hasValue && ( <button onClick={handleClear} style={{ color: "#ef4444" }}> {locale.clear} </button> )} <button onClick={handleCancel}>{locale.cancel}</button> <button onClick={handleConfirm} disabled={!canConfirm} style={{ background: canConfirm ? "#0ea5e9" : "#e5e7eb", color: canConfirm ? "white" : "#9ca3af", padding: "4px 16px", borderRadius: 4, border: "none", }} > {locale.confirm} </button> </div> </div> )} </div> );}Temel Kavramlar
getDayProps
getDayProps fonksiyonu, takvim oluşturmanın merkezindedir. Her tarih hücresi için, hücrenin durumunu tanımlayan 18 boolean/sayı bayrağı içeren bir DayProps nesnesi döndürür:
const dp = getDayProps(day);
// Seçim durumudp.isSelected; // Mevcut seçili tarihdp.isToday; // Bugünün tarihi
// Aralık durumu (aralık seçiciler için)dp.isInRange; // Başlangıç ve bitiş tarihleri arasındadp.isRangeStart; // Aralığın ilk tarihidp.isRangeEnd; // Aralığın son tarihidp.isInHoverRange; // Fare ile üzerine gelinen önizleme aralığındadp.isHoverTarget; // Üzerine gelinen tarihin kendisidp.isRangeSingle; // Hem aralık başlangıcı hem de bitişi (tek günlük aralık)
// Görsel bağlantı yardımcılarıdp.hasLeftConnection; // Önceki güne bağlı (aralık arka planları için)dp.hasRightConnection; // Sonraki güne bağlıdp.isConsecutiveRange; // Çok günlük bir aralığın parçası
// Durumdp.isDisabled; // minDate/maxDate/isDateUnavailable tarafından devre dışı bırakıldıdp.isFocused; // Klavye odağına sahipdp.isOutsideDay; // Bitişik aya ait (showOutsideDays etkinken)dp.isHighlighted; // highlightDates dizisinde
// Veridp.date; // Date nesnesidp.day; // Ayın gün numarasıdp.dayOfWeek; // 0-6 (Pazar-Cumartesi)Dışarı Tıklama için Ref’ler
Hook’lar containerRef ve popupRef döndürür. Bunları sarmalayıcı ve açılır pencere elemanlarınıza ekleyin — hook, bunları dışarıdaki tıklamaları algılamak ve açılır pencereyi otomatik olarak kapatmak için kullanır.
Klavye ile Gezinme
handleKeyDown işleyicisi, tam klavye ile gezinme için ok tuşlarını, Enter, Escape ve Tab tuşlarını destekler. Bunu açılır pencere konteynerine ekleyin.
Yerelleştirme (Locale)
Kullanıcıya dönük tüm metinler locale nesnesinden gelir. Kısmi bir locale seçeneği geçirerek herhangi bir metni özelleştirebilirsiniz:
const picker = useDatePicker({ value, onChange: setValue, locale: { confirm: "Tamam", cancel: "Geri", placeholder: "Bir tarih seçin...", },});Sonraki Adımlar
- Hook Referansı — Her hook için tam seçenekler ve dönüş değerleri
- Context’ler — Bileşik bileşen desenleri için provider’ları kullanın
- Tarih Yardımcıları — Tarih manipülasyonu için yardımcı fonksiyonlar