Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 120 additions & 81 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Building styled and more featured component libraries on top of Dioxus Primitive

We're still in the early days - Many components are still being created and stabilized.

28/28
28/29

- [x] Accordion
- [x] Alert Dialog
Expand All @@ -43,6 +43,7 @@ We're still in the early days - Many components are still being created and stab
- [x] Checkbox
- [x] Collapsible
- [x] Context Menu
- [ ] Date Picker
- [x] Dialog
- [x] Dropdown Menu
- [x] Hover Card
Expand Down
3 changes: 2 additions & 1 deletion component.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"preview/src/components/toggle_group",
"preview/src/components/context_menu",
"preview/src/components/aspect_ratio",
"preview/src/components/scroll_area"
"preview/src/components/scroll_area",
"preview/src/components/date_picker"
]
}
13 changes: 13 additions & 0 deletions preview/src/components/date_picker/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "date_picker",
"description": "A date picker component to select or input dates.",
"authors": ["Evan Almloff"],
"exclude": ["variants", "docs.md", "component.json"],
"cargoDependencies": [
{
"name": "dioxus-primitives",
"git": "https://github.com/DioxusLabs/components"
}
],
"globalAssets": ["../../../assets/dx-components-theme.css"]
}
89 changes: 89 additions & 0 deletions preview/src/components/date_picker/component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use dioxus::prelude::*;

use dioxus_primitives::{
calendar::CalendarProps,
date_picker::{self, DatePickerInputProps, DatePickerProps, DatePickerTriggerProps},
};

use crate::components::calendar::component::*;
use time::UtcDateTime;

#[component]
pub fn DatePicker(props: DatePickerProps) -> Element {
rsx! {
document::Link { rel: "stylesheet", href: asset!("./style.css"), }
div {
date_picker::DatePicker {
class: "date-picker",
value: props.value,
on_value_change: props.on_value_change,
selected_date: props.selected_date,
disabled: props.disabled,
read_only: props.read_only,
separator: props.separator,
on_format_placeholder: props.on_format_placeholder,
attributes: props.attributes,
{props.children}
}
}
}
}

#[component]
pub fn DatePickerInput(props: DatePickerInputProps) -> Element {
rsx! {
date_picker::DatePickerInput {
class: "date-picker-input",
attributes: props.attributes,
{props.children}
}
}
}

#[component]
pub fn DatePickerTrigger(props: DatePickerTriggerProps) -> Element {
rsx! {
date_picker::DatePickerTrigger {
class: "date-picker-trigger",
attributes: props.attributes,
{props.children}
}
}
}

#[component]
pub fn DatePickerCalendar(props: CalendarProps) -> Element {
let mut view_date = use_signal(|| UtcDateTime::now().date());

use_effect(move || {
if let Some(date) = (props.selected_date)() {
view_date.set(date);
}
});

rsx! {
Calendar {
selected_date: props.selected_date,
on_date_change: props.on_date_change,
on_format_weekday: props.on_format_weekday,
on_format_month: props.on_format_month,
view_date: view_date(),
today: props.today,
on_view_change: move |date| view_date.set(date),
disabled: props.disabled,
first_day_of_week: props.first_day_of_week,
min_date: props.min_date,
max_date: props.max_date,
attributes: props.attributes,
CalendarHeader {
CalendarNavigation {
CalendarPreviousMonthButton {}
CalendarSelectMonth {}
CalendarSelectYear {}
CalendarNextMonthButton {}
}
}
CalendarGrid {}
}
}
}
6 changes: 6 additions & 0 deletions preview/src/components/date_picker/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
The DatePicker component is used to display a date input and a Calendar popover, allowing users to enter or select a date value.

## Component Structure

```rust
```
2 changes: 2 additions & 0 deletions preview/src/components/date_picker/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod component;
pub use component::*;
71 changes: 71 additions & 0 deletions preview/src/components/date_picker/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
.date-picker {
position: relative;
display: inline-flex;
align-items: center;
}

.date-picker-input {
position: relative;
display: flex;
box-sizing: border-box;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 0.25rem;
padding: 8px 40px 8px 12px;
border: none;
border-radius: 0.5rem;
border-radius: calc(0.5rem);
background: none;
background: var(--light, var(--primary-color))
var(--dark, var(--primary-color-3));
box-shadow: inset 0 0 0 1px var(--light, var(--primary-color-6))
var(--dark, var(--primary-color-7));
color: var(--secondary-color-4);
gap: 0.25rem;
transition: background-color 100ms ease-out;
}

.date-picker-trigger {
border: none;
background-color: transparent;
cursor: pointer;
position: relative;
margin-left: -35px;
}

.date-picker-input input::placeholder {
color: var(--secondary-color-5);
}

.date-picker[data-state="open"] .date-picker-input {
pointer-events: none;
}

.date-picker-expand-icon {
width: 20px;
height: 20px;
fill: none;
stroke: var(--primary-color-7);
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 2;
}

.date-picker[data-disabled="true"] .date-picker-input {
color: var(--secondary-color-5);
cursor: not-allowed;
}

.date-picker-input:hover:not([data-disabled="true"]),
.date-picker-input:focus-visible {
background: var(--light, var(--primary-color-4))
var(--dark, var(--primary-color-5));
color: var(--secondary-color-1);
outline: none;
}

[data-disabled="true"] {
cursor: not-allowed;
opacity: 0.5;
}
41 changes: 41 additions & 0 deletions preview/src/components/date_picker/variants/main/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use super::super::component::*;
use dioxus::prelude::*;

use dioxus_i18n::tid;
use dioxus_primitives::date_picker::DatePickerValue;

use time::{Date, Month, Weekday};

#[component]
pub fn Demo() -> Element {
let v = DatePickerValue::new_day(None);
let mut value = use_signal(|| v);

let mut selected_date = use_signal(|| None::<Date>);

rsx! {
div {
DatePicker {
value: value(),
selected_date: selected_date(),
on_value_change: move |v| {
tracing::info!("Selected: {v}");
value.set(v);
selected_date.set(v.date());
},
on_format_placeholder: || tid!("YMD"),
DatePickerInput {
DatePickerTrigger {
aria_label: "DatePicker Trigger",
DatePickerCalendar {
selected_date: selected_date(),
on_date_change: move |date| selected_date.set(date),
on_format_weekday: |weekday: Weekday| tid!(&weekday.to_string()),
on_format_month: |month: Month| tid!(&month.to_string()),
}
}
}
}
}
}
}
1 change: 1 addition & 0 deletions preview/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ examples!(
checkbox,
collapsible,
context_menu,
date_picker,
dialog,
dropdown_menu,
hover_card,
Expand Down
5 changes: 4 additions & 1 deletion preview/src/i18n/de-DE.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ Wednesday = Mi
Thursday = Do
Friday = Fr
Saturday = Sa
Sunday = So
Sunday = So

## Date
YMD = JJJJ-MM-TT
5 changes: 4 additions & 1 deletion preview/src/i18n/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ Wednesday = We
Thursday = Th
Friday = Fr
Saturday = Sa
Sunday = Su
Sunday = Su

## Date
YMD = YYYY-MM-DD
5 changes: 4 additions & 1 deletion preview/src/i18n/es-ES.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ Wednesday = Mi
Thursday = Ju
Friday = Vi
Saturday = Sa
Sunday = Do
Sunday = Do

## Date
YMD = YYYY-MM-DD
5 changes: 4 additions & 1 deletion preview/src/i18n/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ Wednesday = Me
Thursday = Je
Friday = Ve
Saturday = Sa
Sunday = Di
Sunday = Di

## Date
YMD = AAAA-MM-JJ
2 changes: 1 addition & 1 deletion primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ repository = "https://github.com/DioxusLabs/components"
[dependencies]
dioxus.workspace = true
dioxus-time = { git = "https://github.com/ealmloff/dioxus-std", branch = "0.7" }
time = { version = "0.3.41", features = ["std", "macros"] }
time = { version = "0.3.41", features = ["std", "macros", "parsing"] }
tracing.workspace = true

[build-dependencies]
Expand Down
34 changes: 20 additions & 14 deletions primitives/src/calendar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ fn previous_month(date: Date) -> Option<Date> {
.ok()
}

fn replace_month(date: Date, month: Month) -> Date {
let year = date.year();
let num_days = month.length(year);
Date::from_calendar_date(year, month, std::cmp::min(date.day(), num_days))
.expect("invalid or out-of-range date")
}

/// The context provided by the [`Calendar`] component to its children.
#[derive(Copy, Clone)]
pub struct CalendarContext {
Expand Down Expand Up @@ -223,6 +230,7 @@ pub struct CalendarProps {
pub on_format_month: Callback<Month, String>,

/// The month being viewed
#[props(default = ReadSignal::new(Signal::new(UtcDateTime::now().date())))]
pub view_date: ReadSignal<Date>,

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

let mut date = view_date;
// Add days of the month
let num_days_in_month = view_date.month().length(view_date.year());
for day in 1..=num_days_in_month {
grid.push(
view_date
.replace_day(day)
.expect("invalid or out-of-range date"),
);
date = view_date
.replace_day(day)
.expect("invalid or out-of-range date");
grid.push(date);
}

// Add empty cells to complete the grid (for a clean layout)
let remainder = grid.len() % 7;
if remainder > 0 {
if let Some(mut date) = next_month(view_date) {
for _ in 1..=(7 - remainder) {
grid.push(date);
date = date.next_day().expect("invalid or out-of-range date");
}
for _ in 1..=(7 - remainder) {
date = date.next_day().expect("invalid or out-of-range date");
grid.push(date);
}
}

Expand Down Expand Up @@ -1027,11 +1033,11 @@ pub fn CalendarSelectMonth(props: CalendarSelectMonthProps) -> Element {
// Get the current view date from context
let view_date = (calendar.view_date)();
let mut min_month = Month::January;
if view_date.replace_month(min_month).unwrap() < calendar.min_date {
if replace_month(view_date, min_month) < calendar.min_date {
min_month = calendar.min_date.month();
}
let mut max_month = Month::December;
if view_date.replace_month(max_month).unwrap() > calendar.max_date {
if replace_month(view_date, max_month) > calendar.max_date {
max_month = calendar.max_date.month();
}

Expand Down Expand Up @@ -1144,11 +1150,11 @@ pub fn CalendarSelectYear(props: CalendarSelectYearProps) -> Element {
let view_date = (calendar.view_date)();
let month = view_date.month();
let mut min_year = calendar.min_date.year();
if calendar.min_date.replace_month(month).unwrap() < calendar.min_date {
if replace_month(calendar.min_date, month) < calendar.min_date {
min_year += 1;
}
let mut max_year = calendar.max_date.year();
if calendar.max_date.replace_month(month).unwrap() > calendar.max_date {
if replace_month(calendar.max_date, month) > calendar.max_date {
max_year -= 1;
}

Expand Down
Loading