Skip to content

Commit 3c56fee

Browse files
committed
[*] DatePicker: implement new functionality
- Add popover with Calendar - Pass Calendar as child - Correct input validation - Split from preview - Fix add Calendar empty cells - Localization
1 parent 4d11d3b commit 3c56fee

File tree

10 files changed

+935
-861
lines changed

10 files changed

+935
-861
lines changed

Cargo.lock

Lines changed: 555 additions & 531 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use crate::components::calendar::component::*;
2+
use dioxus::prelude::*;
3+
4+
use dioxus_primitives::{
5+
calendar::CalendarProps,
6+
date_picker::{self, DatePickerInputProps, DatePickerProps, DatePickerTriggerProps},
7+
};
8+
9+
use time::UtcDateTime;
10+
11+
#[component]
12+
pub fn DatePicker(props: DatePickerProps) -> Element {
13+
rsx! {
14+
document::Link {
15+
rel: "stylesheet",
16+
href: asset!("/src/components/date_picker/style.css"),
17+
}
18+
div {
19+
date_picker::DatePicker {
20+
class: "date-picker",
21+
value: props.value,
22+
on_value_change: props.on_value_change,
23+
selected_date: props.selected_date,
24+
disabled: props.disabled,
25+
read_only: props.read_only,
26+
separator: props.separator,
27+
on_format_placeholder: props.on_format_placeholder,
28+
attributes: props.attributes,
29+
{props.children}
30+
}
31+
}
32+
}
33+
}
34+
35+
#[component]
36+
pub fn DatePickerInput(props: DatePickerInputProps) -> Element {
37+
rsx! {
38+
date_picker::DatePickerInput {
39+
class: "date-picker-input",
40+
attributes: props.attributes,
41+
{props.children}
42+
}
43+
}
44+
}
45+
46+
#[component]
47+
pub fn DatePickerTrigger(props: DatePickerTriggerProps) -> Element {
48+
rsx! {
49+
date_picker::DatePickerTrigger {
50+
class: "date-picker-trigger",
51+
attributes: props.attributes,
52+
{props.children}
53+
}
54+
}
55+
}
56+
57+
#[component]
58+
pub fn DatePickerCalendar(props: CalendarProps) -> Element {
59+
let mut view_date = use_signal(|| UtcDateTime::now().date());
60+
61+
use_effect(move || {
62+
if let Some(date) = (props.selected_date)() {
63+
view_date.set(date);
64+
}
65+
});
66+
67+
rsx! {
68+
Calendar {
69+
selected_date: props.selected_date,
70+
on_date_change: props.on_date_change,
71+
on_format_weekday: props.on_format_weekday,
72+
on_format_month: props.on_format_month,
73+
view_date: view_date(),
74+
today: props.today,
75+
on_view_change: move |date| view_date.set(date),
76+
disabled: props.disabled,
77+
first_day_of_week: props.first_day_of_week,
78+
min_date: props.min_date,
79+
max_date: props.max_date,
80+
attributes: props.attributes,
81+
CalendarHeader {
82+
CalendarNavigation {
83+
CalendarPreviousMonthButton {}
84+
CalendarSelectMonth {}
85+
CalendarSelectYear {}
86+
CalendarNextMonthButton {}
87+
}
88+
}
89+
CalendarGrid {}
90+
}
91+
}
92+
}

preview/src/components/date_picker/variants/main/style.css renamed to preview/src/components/date_picker/style.css

Lines changed: 2 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,16 @@
2222
box-shadow: inset 0 0 0 1px var(--light, var(--primary-color-6))
2323
var(--dark, var(--primary-color-7));
2424
color: var(--secondary-color-4);
25-
cursor: text;
2625
gap: 0.25rem;
2726
transition: background-color 100ms ease-out;
2827
}
2928

3029
.date-picker-trigger {
31-
position: absolute;
32-
right: 0;
3330
border: none;
3431
background-color: transparent;
3532
cursor: pointer;
36-
padding: 0.25rem;
37-
padding: 8px 12px;
33+
position: relative;
34+
margin-left: -35px;
3835
}
3936

4037
.date-picker-input input::placeholder {
@@ -68,58 +65,6 @@
6865
outline: none;
6966
}
7067

71-
.date-picker-calendar {
72-
position: absolute;
73-
z-index: 1000;
74-
top: 100%;
75-
left: 0;
76-
min-width: 100%;
77-
box-sizing: border-box;
78-
padding: 0.25rem;
79-
border-radius: 0.5rem;
80-
margin-top: 0.25rem;
81-
background: var(--light, var(--primary-color))
82-
var(--dark, var(--primary-color-5));
83-
box-shadow: inset 0 0 0 1px var(--light, var(--primary-color-6))
84-
var(--dark, var(--primary-color-7));
85-
transform-origin: top;
86-
opacity: 0;
87-
pointer-events: none;
88-
will-change: transform, opacity;
89-
}
90-
91-
.date-picker-calendar[data-state="closed"] {
92-
pointer-events: none;
93-
animation: date-picker-calendar-animate-out 150ms ease-in forwards;
94-
}
95-
96-
@keyframes date-picker-calendar-animate-out {
97-
0% {
98-
opacity: 1;
99-
transform: scale(1) translateY(0);
100-
}
101-
100% {
102-
opacity: 0;
103-
transform: scale(0.95) translateY(-2px);
104-
}
105-
}
106-
107-
.date-picker-calendar[data-state="open"] {
108-
pointer-events: auto;
109-
animation: date-picker-calendar-animate-in 150ms ease-out forwards;
110-
}
111-
112-
@keyframes date-picker-calendar-animate-in {
113-
0% {
114-
opacity: 0;
115-
transform: scale(0.95) translateY(-2px);
116-
}
117-
100% {
118-
opacity: 1;
119-
transform: scale(1) translateY(0);
120-
}
121-
}
122-
12368
[data-disabled="true"] {
12469
cursor: not-allowed;
12570
opacity: 0.5;

preview/src/components/date_picker/variants/main/mod.rs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
1+
use super::super::component::*;
12
use dioxus::prelude::*;
2-
use dioxus_primitives::date_picker::{
3-
DatePicker, DatePickerCalendar, DatePickerInput, DatePickerTrigger, DatePickerValue,
4-
};
3+
4+
use dioxus_i18n::tid;
5+
use dioxus_primitives::date_picker::DatePickerValue;
6+
7+
use time::{Date, Month, Weekday};
58

69
#[component]
710
pub fn Demo() -> Element {
8-
let mut value = use_signal(|| None::<DatePickerValue>);
11+
let v = DatePickerValue::new_day(None);
12+
let mut value = use_signal(|| v);
13+
14+
let mut selected_date = use_signal(|| None::<Date>);
915

1016
rsx! {
11-
document::Link {
12-
rel: "stylesheet",
13-
href: asset!("/src/components/date_picker/variants/main/style.css"),
14-
}
1517
div {
1618
DatePicker {
17-
class: "date-picker",
1819
value: value(),
19-
on_value_change: move |date| {
20-
tracing::info!("Selected date: {:?}", date);
21-
value.set(date);
20+
selected_date: selected_date(),
21+
on_value_change: move |v| {
22+
tracing::info!("Selected: {v}");
23+
value.set(v);
24+
selected_date.set(v.date());
2225
},
26+
on_format_placeholder: || tid!("YMD"),
2327
DatePickerInput {
24-
class: "date-picker-input",
2528
DatePickerTrigger {
26-
class: "date-picker-trigger",
27-
aria_label: "DatePicker Trigger",
28-
svg {
29-
class: "date-picker-expand-icon",
30-
view_box: "0 0 24 24",
31-
xmlns: "http://www.w3.org/2000/svg",
32-
polyline { points: "6 9 12 15 18 9" }
29+
aria_label: "DatePicker Trigger",
30+
DatePickerCalendar {
31+
selected_date: selected_date(),
32+
on_date_change: move |date| selected_date.set(date),
33+
on_format_weekday: |weekday: Weekday| tid!(&weekday.to_string()),
34+
on_format_month: |month: Month| tid!(&month.to_string()),
35+
}
3336
}
3437
}
35-
}
36-
DatePickerCalendar { class: "date-picker-calendar" }
3738
}
3839
}
3940
}

preview/src/i18n/de-DE.ftl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ Wednesday = Mi
1919
Thursday = Do
2020
Friday = Fr
2121
Saturday = Sa
22-
Sunday = So
22+
Sunday = So
23+
24+
## Date
25+
YMD = JJJJ-MM-TT

preview/src/i18n/en-US.ftl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ Wednesday = We
1919
Thursday = Th
2020
Friday = Fr
2121
Saturday = Sa
22-
Sunday = Su
22+
Sunday = Su
23+
24+
## Date
25+
YMD = YYYY-MM-DD

preview/src/i18n/es-ES.ftl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ Wednesday = Mi
1919
Thursday = Ju
2020
Friday = Vi
2121
Saturday = Sa
22-
Sunday = Do
22+
Sunday = Do
23+
24+
## Date
25+
YMD = YYYY-MM-DD

preview/src/i18n/fr-FR.ftl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ Wednesday = Me
1919
Thursday = Je
2020
Friday = Ve
2121
Saturday = Sa
22-
Sunday = Di
22+
Sunday = Di
23+
24+
## Date
25+
YMD = AAAA-MM-JJ

primitives/src/calendar.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ pub struct CalendarProps {
230230
pub on_format_month: Callback<Month, String>,
231231

232232
/// The month being viewed
233+
#[props(default = ReadOnlySignal::new(Signal::new(UtcDateTime::now().date())))]
233234
pub view_date: ReadOnlySignal<Date>,
234235

235236
/// The current date (used for highlighting today)
@@ -896,24 +897,22 @@ pub fn CalendarGrid(props: CalendarGridProps) -> Element {
896897
date = date.next_day().expect("invalid or out-of-range date");
897898
}
898899

900+
let mut date = view_date;
899901
// Add days of the month
900902
let num_days_in_month = view_date.month().length(view_date.year());
901903
for day in 1..=num_days_in_month {
902-
grid.push(
903-
view_date
904-
.replace_day(day)
905-
.expect("invalid or out-of-range date"),
906-
);
904+
date = view_date
905+
.replace_day(day)
906+
.expect("invalid or out-of-range date");
907+
grid.push(date);
907908
}
908909

909910
// Add empty cells to complete the grid (for a clean layout)
910911
let remainder = grid.len() % 7;
911912
if remainder > 0 {
912-
if let Some(mut date) = next_month(view_date) {
913-
for _ in 1..=(7 - remainder) {
914-
grid.push(date);
915-
date = date.next_day().expect("invalid or out-of-range date");
916-
}
913+
for _ in 1..=(7 - remainder) {
914+
date = date.next_day().expect("invalid or out-of-range date");
915+
grid.push(date);
917916
}
918917
}
919918

0 commit comments

Comments
 (0)