https://github.com/longbridge/gpui-component/pull/1502#issuecomment-3485354324 ## Break Change - The `DatePicker` and `Select` has changed `cleanable` default from `true` to `false`. - Updated `Input`, `DatePicker` and `Select` the `cleanable` to have a argument. ```diff - pub fn cleanable(mut self) + pub fn cleanable(mut self, cleanable: bool) ``` --------- Co-authored-by: Jason Lee <huacnlee@gmail.com>
412 lines
9.2 KiB
Markdown
412 lines
9.2 KiB
Markdown
---
|
|
title: DatePicker
|
|
description: A date picker component for selecting single dates or date ranges with calendar interface.
|
|
---
|
|
|
|
# DatePicker
|
|
|
|
A flexible date picker component with calendar interface that supports single date selection, date range selection, custom date formatting, disabled dates, and preset ranges.
|
|
|
|
## Import
|
|
|
|
```rust
|
|
use gpui_component::{
|
|
date_picker::{DatePicker, DatePickerState, DateRangePreset, DatePickerEvent},
|
|
calendar::{Date, Matcher},
|
|
};
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Basic Date Picker
|
|
|
|
```rust
|
|
let date_picker = cx.new(|cx| DatePickerState::new(window, cx));
|
|
|
|
DatePicker::new(&date_picker)
|
|
```
|
|
|
|
### With Initial Date
|
|
|
|
```rust
|
|
use chrono::Local;
|
|
|
|
let date_picker = cx.new(|cx| {
|
|
let mut picker = DatePickerState::new(window, cx);
|
|
picker.set_date(Local::now().naive_local().date(), window, cx);
|
|
picker
|
|
});
|
|
|
|
DatePicker::new(&date_picker)
|
|
```
|
|
|
|
### Date Range Picker
|
|
|
|
```rust
|
|
use chrono::{Local, Days};
|
|
|
|
// Range mode picker
|
|
let range_picker = cx.new(|cx| DatePickerState::range(window, cx));
|
|
|
|
DatePicker::new(&range_picker)
|
|
.number_of_months(2) // Show 2 months for easier range selection
|
|
|
|
// With initial range
|
|
let range_picker = cx.new(|cx| {
|
|
let now = Local::now().naive_local().date();
|
|
let mut picker = DatePickerState::new(window, cx);
|
|
picker.set_date(
|
|
(now, now.checked_add_days(Days::new(7)).unwrap()),
|
|
window,
|
|
cx,
|
|
);
|
|
picker
|
|
});
|
|
|
|
DatePicker::new(&range_picker)
|
|
.number_of_months(2)
|
|
```
|
|
|
|
### With Custom Date Format
|
|
|
|
```rust
|
|
let date_picker = cx.new(|cx| {
|
|
DatePickerState::new(window, cx)
|
|
.date_format("%Y-%m-%d") // ISO format
|
|
});
|
|
|
|
DatePicker::new(&date_picker)
|
|
|
|
// Other format examples:
|
|
// "%m/%d/%Y" -> 12/25/2023
|
|
// "%B %d, %Y" -> December 25, 2023
|
|
// "%d %b %Y" -> 25 Dec 2023
|
|
```
|
|
|
|
### With Placeholder
|
|
|
|
```rust
|
|
DatePicker::new(&date_picker)
|
|
.placeholder("Select a date...")
|
|
```
|
|
|
|
### Cleanable Date Picker
|
|
|
|
```rust
|
|
DatePicker::new(&date_picker)
|
|
.cleanable(true) // Show clear button when date is selected
|
|
```
|
|
|
|
### Different Sizes
|
|
|
|
```rust
|
|
DatePicker::new(&date_picker).large()
|
|
DatePicker::new(&date_picker) // medium (default)
|
|
DatePicker::new(&date_picker).small()
|
|
```
|
|
|
|
### Disabled State
|
|
|
|
```rust
|
|
DatePicker::new(&date_picker).disabled(true)
|
|
```
|
|
|
|
### Custom Appearance
|
|
|
|
```rust
|
|
// Without default styling
|
|
DatePicker::new(&date_picker).appearance(false)
|
|
|
|
// Use in custom container
|
|
div()
|
|
.border_b_2()
|
|
.px_6()
|
|
.py_3()
|
|
.border_color(cx.theme().border)
|
|
.bg(cx.theme().secondary)
|
|
.child(DatePicker::new(&date_picker).appearance(false))
|
|
```
|
|
|
|
## Date Restrictions
|
|
|
|
### Disabled Weekends
|
|
|
|
```rust
|
|
use gpui_component::calendar;
|
|
|
|
let date_picker = cx.new(|cx| {
|
|
DatePickerState::new(window, cx)
|
|
.disabled_matcher(vec![0, 6]) // Sunday=0, Saturday=6
|
|
});
|
|
|
|
DatePicker::new(&date_picker)
|
|
```
|
|
|
|
### Disabled Date Range
|
|
|
|
```rust
|
|
use chrono::{Local, Days};
|
|
|
|
let now = Local::now().naive_local().date();
|
|
|
|
let date_picker = cx.new(|cx| {
|
|
DatePickerState::new(window, cx)
|
|
.disabled_matcher(calendar::Matcher::range(
|
|
Some(now),
|
|
now.checked_add_days(Days::new(7)),
|
|
))
|
|
});
|
|
|
|
DatePicker::new(&date_picker)
|
|
```
|
|
|
|
### Disabled Date Interval
|
|
|
|
```rust
|
|
let date_picker = cx.new(|cx| {
|
|
DatePickerState::new(window, cx)
|
|
.disabled_matcher(calendar::Matcher::interval(
|
|
Some(now),
|
|
now.checked_add_days(Days::new(5))
|
|
))
|
|
});
|
|
|
|
DatePicker::new(&date_picker)
|
|
```
|
|
|
|
### Custom Disabled Dates
|
|
|
|
```rust
|
|
// Disable first 5 days of each month
|
|
let date_picker = cx.new(|cx| {
|
|
DatePickerState::new(window, cx)
|
|
.disabled_matcher(calendar::Matcher::custom(|date| {
|
|
date.day0() < 5
|
|
}))
|
|
});
|
|
|
|
DatePicker::new(&date_picker)
|
|
|
|
// Disable all Mondays
|
|
let date_picker = cx.new(|cx| {
|
|
DatePickerState::new(window, cx)
|
|
.disabled_matcher(calendar::Matcher::custom(|date| {
|
|
date.weekday() == chrono::Weekday::Mon
|
|
}))
|
|
});
|
|
```
|
|
|
|
## Preset Ranges
|
|
|
|
### Single Date Presets
|
|
|
|
```rust
|
|
use chrono::{Utc, Duration};
|
|
|
|
let presets = vec![
|
|
DateRangePreset::single(
|
|
"Yesterday",
|
|
(Utc::now() - Duration::days(1)).naive_local().date(),
|
|
),
|
|
DateRangePreset::single(
|
|
"Last Week",
|
|
(Utc::now() - Duration::weeks(1)).naive_local().date(),
|
|
),
|
|
DateRangePreset::single(
|
|
"Last Month",
|
|
(Utc::now() - Duration::days(30)).naive_local().date(),
|
|
),
|
|
];
|
|
|
|
DatePicker::new(&date_picker)
|
|
.presets(presets)
|
|
```
|
|
|
|
### Date Range Presets
|
|
|
|
```rust
|
|
let range_presets = vec![
|
|
DateRangePreset::range(
|
|
"Last 7 Days",
|
|
(Utc::now() - Duration::days(7)).naive_local().date(),
|
|
Utc::now().naive_local().date(),
|
|
),
|
|
DateRangePreset::range(
|
|
"Last 30 Days",
|
|
(Utc::now() - Duration::days(30)).naive_local().date(),
|
|
Utc::now().naive_local().date(),
|
|
),
|
|
DateRangePreset::range(
|
|
"Last 90 Days",
|
|
(Utc::now() - Duration::days(90)).naive_local().date(),
|
|
Utc::now().naive_local().date(),
|
|
),
|
|
];
|
|
|
|
DatePicker::new(&date_picker)
|
|
.number_of_months(2)
|
|
.presets(range_presets)
|
|
```
|
|
|
|
## Handle Date Selection Events
|
|
|
|
```rust
|
|
let date_picker = cx.new(|cx| DatePickerState::new(window, cx));
|
|
|
|
cx.subscribe(&date_picker, |view, _, event, _| {
|
|
match event {
|
|
DatePickerEvent::Change(date) => {
|
|
match date {
|
|
Date::Single(Some(selected_date)) => {
|
|
println!("Single date selected: {}", selected_date);
|
|
}
|
|
Date::Range(Some(start), Some(end)) => {
|
|
println!("Date range selected: {} to {}", start, end);
|
|
}
|
|
Date::Range(Some(start), None) => {
|
|
println!("Range start selected: {}", start);
|
|
}
|
|
_ => {
|
|
println!("Date cleared");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
```
|
|
|
|
## Multiple Months Display
|
|
|
|
```rust
|
|
// Show 2 months side by side (useful for date ranges)
|
|
DatePicker::new(&date_picker)
|
|
.number_of_months(2)
|
|
|
|
// Show 3 months
|
|
DatePicker::new(&date_picker)
|
|
.number_of_months(3)
|
|
```
|
|
|
|
## Advanced Examples
|
|
|
|
### Business Days Only
|
|
|
|
```rust
|
|
use chrono::Weekday;
|
|
|
|
let business_days_picker = cx.new(|cx| {
|
|
DatePickerState::new(window, cx)
|
|
.disabled_matcher(calendar::Matcher::custom(|date| {
|
|
matches!(date.weekday(), Weekday::Sat | Weekday::Sun)
|
|
}))
|
|
});
|
|
|
|
DatePicker::new(&business_days_picker)
|
|
.placeholder("Select business day")
|
|
```
|
|
|
|
### Date Range with Max Duration
|
|
|
|
```rust
|
|
use chrono::Days;
|
|
|
|
let max_30_days_picker = cx.new(|cx| DatePickerState::range(window, cx));
|
|
|
|
cx.subscribe(&max_30_days_picker, |view, picker, event, _| {
|
|
match event {
|
|
DatePickerEvent::Change(Date::Range(Some(start), Some(end))) => {
|
|
let duration = end.signed_duration_since(*start).num_days();
|
|
if duration > 30 {
|
|
// Reset to start date only if range exceeds 30 days
|
|
picker.update(cx, |state, cx| {
|
|
state.set_date(Date::Range(Some(*start), None), window, cx);
|
|
});
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
});
|
|
|
|
DatePicker::new(&max_30_days_picker)
|
|
.number_of_months(2)
|
|
.placeholder("Select up to 30 days")
|
|
```
|
|
|
|
### Quarter Presets
|
|
|
|
```rust
|
|
use chrono::{NaiveDate, Datelike};
|
|
|
|
fn quarter_start(year: i32, quarter: u32) -> NaiveDate {
|
|
let month = (quarter - 1) * 3 + 1;
|
|
NaiveDate::from_ymd_opt(year, month, 1).unwrap()
|
|
}
|
|
|
|
fn quarter_end(year: i32, quarter: u32) -> NaiveDate {
|
|
let month = quarter * 3;
|
|
let start = NaiveDate::from_ymd_opt(year, month, 1).unwrap();
|
|
NaiveDate::from_ymd_opt(year, month, start.days_in_month()).unwrap()
|
|
}
|
|
|
|
let year = Local::now().year();
|
|
let quarterly_presets = vec![
|
|
DateRangePreset::range("Q1", quarter_start(year, 1), quarter_end(year, 1)),
|
|
DateRangePreset::range("Q2", quarter_start(year, 2), quarter_end(year, 2)),
|
|
DateRangePreset::range("Q3", quarter_start(year, 3), quarter_end(year, 3)),
|
|
DateRangePreset::range("Q4", quarter_start(year, 4), quarter_end(year, 4)),
|
|
];
|
|
|
|
DatePicker::new(&date_picker)
|
|
.presets(quarterly_presets)
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Event Date Picker
|
|
|
|
```rust
|
|
let event_date = cx.new(|cx| {
|
|
let mut picker = DatePickerState::new(window, cx)
|
|
.date_format("%B %d, %Y")
|
|
.disabled_matcher(calendar::Matcher::custom(|date| {
|
|
// Disable past dates
|
|
*date < Local::now().naive_local().date()
|
|
}));
|
|
picker
|
|
});
|
|
|
|
DatePicker::new(&event_date)
|
|
.placeholder("Choose event date")
|
|
.cleanable(true)
|
|
```
|
|
|
|
### Booking System Date Range
|
|
|
|
```rust
|
|
let booking_range = cx.new(|cx| DatePickerState::range(window, cx));
|
|
|
|
let booking_presets = vec![
|
|
DateRangePreset::range("This Weekend", /* weekend dates */),
|
|
DateRangePreset::range("Next Week", /* next week dates */),
|
|
DateRangePreset::range("This Month", /* this month dates */),
|
|
];
|
|
|
|
DatePicker::new(&booking_range)
|
|
.number_of_months(2)
|
|
.presets(booking_presets)
|
|
.placeholder("Select check-in and check-out dates")
|
|
```
|
|
|
|
### Financial Period Selector
|
|
|
|
```rust
|
|
let financial_period = cx.new(|cx| {
|
|
DatePickerState::range(window, cx)
|
|
.date_format("%Y-%m-%d")
|
|
});
|
|
|
|
DatePicker::new(&financial_period)
|
|
.number_of_months(3)
|
|
.presets(quarterly_presets)
|
|
.placeholder("Select reporting period")
|
|
```
|