-
Notifications
You must be signed in to change notification settings - Fork 290
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add date picker and date range picker components. (#982)
- Loading branch information
1 parent
3631e14
commit 429fa93
Showing
36 changed files
with
1,042 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from dataclasses import field | ||
from datetime import date | ||
|
||
import mesop as me | ||
|
||
|
||
@me.stateclass | ||
class State: | ||
picked_date: date | None = field(default_factory=lambda: date(2024, 10, 1)) | ||
|
||
|
||
def on_load(e: me.LoadEvent): | ||
me.set_theme_mode("system") | ||
|
||
|
||
@me.page(path="/date_picker", on_load=on_load) | ||
def app(): | ||
state = me.state(State) | ||
with me.box( | ||
style=me.Style( | ||
display="flex", | ||
flex_direction="column", | ||
gap=15, | ||
padding=me.Padding.all(15), | ||
) | ||
): | ||
me.date_picker( | ||
label="Date", | ||
disabled=False, | ||
placeholder="9/1/2024", | ||
required=True, | ||
value=state.picked_date, | ||
readonly=False, | ||
hide_required_marker=False, | ||
color="accent", | ||
float_label="always", | ||
appearance="outline", | ||
on_change=on_date_change, | ||
) | ||
|
||
me.text("Selected date: " + _render_date(state.picked_date)) | ||
|
||
|
||
def on_date_change(e: me.DatePickerChangeEvent): | ||
state = me.state(State) | ||
state.picked_date = e.date | ||
|
||
|
||
def _render_date(maybe_date: date | None) -> str: | ||
if maybe_date: | ||
return maybe_date.strftime("%Y-%m-%d") | ||
return "None" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from dataclasses import field | ||
from datetime import date | ||
|
||
import mesop as me | ||
|
||
|
||
@me.stateclass | ||
class State: | ||
picked_start_date: date | None = field( | ||
default_factory=lambda: date(2024, 10, 1) | ||
) | ||
picked_end_date: date | None = field( | ||
default_factory=lambda: date(2024, 11, 1) | ||
) | ||
|
||
|
||
def on_load(e: me.LoadEvent): | ||
me.set_theme_mode("system") | ||
|
||
|
||
@me.page(path="/date_range_picker", on_load=on_load) | ||
def app(): | ||
state = me.state(State) | ||
with me.box( | ||
style=me.Style( | ||
display="flex", | ||
flex_direction="column", | ||
gap=15, | ||
padding=me.Padding.all(15), | ||
) | ||
): | ||
me.date_range_picker( | ||
label="Date Range", | ||
disabled=False, | ||
placeholder_start_date="9/1/2024", | ||
placeholder_end_date="10/1/2024", | ||
required=True, | ||
start_date=state.picked_start_date, | ||
end_date=state.picked_end_date, | ||
readonly=False, | ||
hide_required_marker=False, | ||
color="accent", | ||
float_label="always", | ||
appearance="outline", | ||
on_change=on_date_range_change, | ||
) | ||
|
||
me.text("Start date: " + _render_date(state.picked_start_date)) | ||
me.text("End date: " + _render_date(state.picked_end_date)) | ||
|
||
|
||
def on_date_range_change(e: me.DateRangePickerChangeEvent): | ||
state = me.state(State) | ||
state.picked_start_date = e.start_date | ||
state.picked_end_date = e.end_date | ||
|
||
|
||
def _render_date(maybe_date: date | None) -> str: | ||
if maybe_date: | ||
return maybe_date.strftime("%Y-%m-%d") | ||
return "None" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
## Overview | ||
|
||
Date picker allows the user to enter free text or select a date from a calendar widget. | ||
and is based on the [Angular Material datapicker component](https://material.angular.io/components/datepicker/overview). | ||
|
||
## Examples | ||
|
||
<iframe class="component-demo" src="https://google.github.io/mesop/demo/?demo=date_picker" style="height: 200px"></iframe> | ||
|
||
```python | ||
--8<-- "demo/date_picker.py" | ||
``` | ||
|
||
## API | ||
|
||
::: mesop.components.datepicker.datepicker.date_picker | ||
::: mesop.components.datepicker.datepicker.DatePickerChangeEvent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
## Overview | ||
|
||
Date range picker allows the user to enter free text or select a dates from a calendar widget. | ||
and is based on the [Angular Material datapicker component](https://material.angular.io/components/datepicker/overview). | ||
|
||
## Examples | ||
|
||
<iframe class="component-demo" src="https://google.github.io/mesop/demo/?demo=date_range_picker" style="height: 200px"></iframe> | ||
|
||
```python | ||
--8<-- "demo/date_range_picker.py" | ||
``` | ||
|
||
## API | ||
|
||
::: mesop.components.date_range_picker.date_range_picker.date_range_picker | ||
::: mesop.components.date_range_picker.date_range_picker.DateRangePickerChangeEvent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
load("//mesop/components:defs.bzl", "mesop_component") | ||
|
||
package( | ||
default_visibility = ["//build_defs:mesop_internal"], | ||
) | ||
|
||
mesop_component( | ||
name = "date_range_picker", | ||
) |
Empty file.
36 changes: 36 additions & 0 deletions
36
mesop/components/date_range_picker/date_range_picker.ng.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<mat-form-field | ||
[hideRequiredMarker]="config().getHideRequiredMarker()!" | ||
[color]="getColor()" | ||
[floatLabel]="getFloatLabel()" | ||
[appearance]="getAppearance()" | ||
[subscriptSizing]="getSubscriptSizing()" | ||
[style]="getStyle()" | ||
> | ||
<mat-label *ngIf="config().getLabel()">{{config().getLabel()}}</mat-label> | ||
<mat-date-range-input | ||
[formGroup]="dateRange" | ||
[rangePicker]="dp" | ||
[required]="config().getRequired()!" | ||
[disabled]="config().getDisabled()!" | ||
> | ||
<input | ||
matStartDate | ||
formControlName="start" | ||
[readonly]="config().getReadonly()!" | ||
[placeholder]="config().getPlaceholderStartDate()!" | ||
(dateChange)="onChange($event)" | ||
/> | ||
<input | ||
matEndDate | ||
formControlName="end" | ||
[readonly]="config().getReadonly()!" | ||
[placeholder]="config().getPlaceholderEndDate()!" | ||
(dateChange)="onChange($event)" | ||
/> | ||
</mat-date-range-input> | ||
<mat-hint *ngIf="config().getHintLabel()"> | ||
{{ config().getHintLabel() }} | ||
</mat-hint> | ||
<mat-datepicker-toggle matIconSuffix [for]="dp"></mat-datepicker-toggle> | ||
<mat-date-range-picker #dp></mat-date-range-picker> | ||
</mat-form-field> |
22 changes: 22 additions & 0 deletions
22
mesop/components/date_range_picker/date_range_picker.proto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
syntax = "proto2"; | ||
|
||
package mesop.components.date_range_picker; | ||
|
||
// Next ID: 16 | ||
message DateRangePickerType { | ||
optional string start_date = 1; | ||
optional string end_date = 2; | ||
optional string placeholder_start_date = 3; | ||
optional string placeholder_end_date = 4; | ||
optional bool disabled = 5; | ||
optional bool required = 6; | ||
optional bool readonly = 7; | ||
optional bool hide_required_marker = 8; | ||
optional string color = 9; | ||
optional string float_label = 10; | ||
optional string appearance = 11; | ||
optional string subscript_sizing = 12; | ||
optional string hint_label = 13; | ||
optional string label = 14; | ||
optional string on_change_handler_id = 15; | ||
} |
122 changes: 122 additions & 0 deletions
122
mesop/components/date_range_picker/date_range_picker.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
from dataclasses import dataclass | ||
from datetime import date, datetime | ||
from typing import Any, Callable, Literal | ||
|
||
import mesop.components.date_range_picker.date_range_picker_pb2 as date_range_picker_pb | ||
from mesop.component_helpers import ( | ||
Style, | ||
insert_component, | ||
register_event_handler, | ||
register_event_mapper, | ||
register_native_component, | ||
) | ||
from mesop.events import MesopEvent | ||
|
||
_DATE_FORMAT = "%Y-%m-%d" | ||
|
||
|
||
@dataclass(kw_only=True) | ||
class DateRangePickerChangeEvent(MesopEvent): | ||
"""Represents a date range picker change event. | ||
This event will only fire if start and end dates are valid dates. | ||
Attributes: | ||
start_date: Start date | ||
end_date: End date | ||
key (str): key of the component that emitted this event. | ||
""" | ||
|
||
start_date: date | ||
end_date: date | ||
|
||
|
||
register_event_mapper( | ||
DateRangePickerChangeEvent, | ||
lambda userEvent, key: DateRangePickerChangeEvent( | ||
start_date=_try_make_date(userEvent.date_range_picker_event.start_date), | ||
end_date=_try_make_date(userEvent.date_range_picker_event.end_date), | ||
key=key.key, | ||
), | ||
) | ||
|
||
|
||
@register_native_component | ||
def date_range_picker( | ||
*, | ||
label: str = "", | ||
on_change: Callable[[DateRangePickerChangeEvent], Any] | None = None, | ||
appearance: Literal["fill", "outline"] = "fill", | ||
style: Style | None = None, | ||
disabled: bool = False, | ||
placeholder_start_date: str = "", | ||
placeholder_end_date: str = "", | ||
required: bool = False, | ||
start_date: date | None = None, | ||
end_date: date | None = None, | ||
readonly: bool = False, | ||
hide_required_marker: bool = False, | ||
color: Literal["primary", "accent", "warn"] = "primary", | ||
float_label: Literal["always", "auto"] = "auto", | ||
subscript_sizing: Literal["fixed", "dynamic"] = "fixed", | ||
hint_label: str = "", | ||
key: str | None = None, | ||
): | ||
"""Creates a date range picker component. | ||
Args: | ||
label: Label for date range picker input. | ||
on_change: Fires when valid date values for both start/end have been specified through Calendar date selection or user input blur. | ||
appearance: The form field appearance style. | ||
style: Style for date range picker input. | ||
disabled: Whether it's disabled. | ||
placeholder_start_date: Start date placeholder value. | ||
placeholder_end_date: End date placeholder value. | ||
required: Whether it's required. | ||
start_date: Start date initial value. | ||
end_date: End date initial value. | ||
readonly: Whether the element is readonly. | ||
hide_required_marker: Whether the required marker should be hidden. | ||
color: The color palette for the form field. | ||
float_label: Whether the label should always float or float as the user types. | ||
subscript_sizing: Whether the form field should reserve space for one line of hint/error text (default) or to have the spacing grow from 0px as needed based on the size of the hint/error content. Note that when using dynamic sizing, layout shifts will occur when hint/error text changes. | ||
hint_label: Text for the form field hint. | ||
key: The component [key](../components/index.md#component-key). | ||
""" | ||
|
||
insert_component( | ||
key=key, | ||
type_name="date_range_picker", | ||
proto=date_range_picker_pb.DateRangePickerType( | ||
start_date=_try_make_date_str(start_date), | ||
end_date=_try_make_date_str(end_date), | ||
placeholder_start_date=placeholder_start_date, | ||
placeholder_end_date=placeholder_end_date, | ||
disabled=disabled, | ||
required=required, | ||
readonly=readonly, | ||
hide_required_marker=hide_required_marker, | ||
color=color, | ||
float_label=float_label, | ||
appearance=appearance, | ||
subscript_sizing=subscript_sizing, | ||
hint_label=hint_label, | ||
label=label, | ||
on_change_handler_id=register_event_handler( | ||
on_change, event=DateRangePickerChangeEvent | ||
) | ||
if on_change | ||
else "", | ||
), | ||
style=style, | ||
) | ||
|
||
|
||
def _try_make_date_str(date_input: date | None) -> str: | ||
if date_input: | ||
return date_input.isoformat() | ||
return "" | ||
|
||
|
||
def _try_make_date(date_string: str) -> date: | ||
return datetime.strptime(date_string, _DATE_FORMAT).date() |
Oops, something went wrong.