Skip to content

Commit d5b5f28

Browse files
committed
st.date widget
1 parent 0d98019 commit d5b5f28

File tree

11 files changed

+106
-15
lines changed

11 files changed

+106
-15
lines changed

examples/widgets.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,9 @@
3434
st.write(w7)
3535

3636
st.subheader('Time')
37-
w8 = st.time('HH:MM', '12:00')
37+
w8 = st.time('Set an alarm for', '12:00')
3838
st.write(w8)
39+
40+
st.subheader('Date')
41+
w9 = st.date('A date to celebrate', '1994/04/06')
42+
st.write(w9)

frontend/src/components/core/ReportView/ReportView.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ import Text from 'components/elements/Text'
2525
// Lazy-load display widgets.
2626
const Button = React.lazy(() => import('components/widgets/Button/'))
2727
const Checkbox = React.lazy(() => import('components/widgets/Checkbox/'))
28+
const DatePicker = React.lazy(() => import('components/widgets/DatePicker/'))
2829
const Input = React.lazy(() => import('components/widgets/Input/'))
2930
const Radio = React.lazy(() => import('components/widgets/Radio/'))
3031
const Select = React.lazy(() => import('components/widgets/Select/'))
3132
const Slider = React.lazy(() => import('components/widgets/Slider/'))
3233
const TextArea = React.lazy(() => import('components/widgets/TextArea/'))
33-
const Time = React.lazy(() => import('components/widgets/Time/'))
34+
const TimePicker = React.lazy(() => import('components/widgets/TimePicker/'))
3435

3536
// Lazy-load display elements.
3637
const Audio = React.lazy(() => import('components/elements/Audio/'))
@@ -178,12 +179,13 @@ export class ReportView extends PureComponent<Props> {
178179
video: (el: Element) => <Video element={el} width={width} />,
179180
button: (el: Element) => <Button element={el} width={width} widgetMgr={this.props.widgetMgr} />,
180181
checkbox: (el: Element) => <Checkbox element={el} width={width} widgetMgr={this.props.widgetMgr} />,
182+
date: (el: Element) => <DatePicker element={el} width={width} widgetMgr={this.props.widgetMgr} />,
181183
input: (el: Element) => <Input element={el} width={width} widgetMgr={this.props.widgetMgr} />,
182184
radio: (el: Element) => <Radio element={el} width={width} widgetMgr={this.props.widgetMgr} />,
183185
select: (el: Element) => <Select element={el} width={width} widgetMgr={this.props.widgetMgr} />,
184186
slider: (el: Element) => <Slider element={el} width={width} widgetMgr={this.props.widgetMgr} />,
185187
textArea: (el: Element) => <TextArea element={el} width={width} widgetMgr={this.props.widgetMgr} />,
186-
time: (el: Element) => <Time element={el} width={width} widgetMgr={this.props.widgetMgr} />,
188+
time: (el: Element) => <TimePicker element={el} width={width} widgetMgr={this.props.widgetMgr} />,
187189
})
188190
}
189191
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Streamlit Inc. All rights reserved.
4+
*/
5+
6+
import React from 'react'
7+
import { Datepicker as UIDatePicker } from 'baseui/datepicker'
8+
import { Map as ImmutableMap } from 'immutable'
9+
import moment from 'moment'
10+
import { WidgetStateManager } from 'lib/WidgetStateManager'
11+
import { PureStreamlitElement, StState } from 'components/shared/StreamlitElement/'
12+
13+
interface Props {
14+
element: ImmutableMap<string, any>;
15+
widgetMgr: WidgetStateManager;
16+
width: number;
17+
}
18+
19+
interface State extends StState {
20+
value: Date;
21+
}
22+
23+
class DatePicker extends PureStreamlitElement<Props, State> {
24+
public constructor(props: Props) {
25+
super(props)
26+
27+
const widgetId = this.props.element.get('id')
28+
const value = this.props.element.get('value')
29+
30+
this.state = {
31+
value: moment(value, 'YYYY/MM/DD').toDate()
32+
}
33+
this.props.widgetMgr.setStringValue(widgetId, value)
34+
this.props.widgetMgr.sendUpdateWidgetsMessage()
35+
}
36+
37+
private dateToString = (date: Date): string => {
38+
return moment(date).format('YYYY/MM/DD')
39+
}
40+
41+
private handleChange = (e: any): void => {
42+
const widgetId = this.props.element.get('id')
43+
44+
this.setState({ value: e.date })
45+
this.props.widgetMgr.setStringValue(widgetId, this.dateToString(e.date))
46+
this.props.widgetMgr.sendUpdateWidgetsMessage()
47+
}
48+
49+
public safeRender(): React.ReactNode {
50+
const label = this.props.element.get('label')
51+
const style = { width: this.props.width }
52+
53+
return (
54+
<div className="Widget stDate" style={style}>
55+
<p className="label">{label}</p>
56+
<UIDatePicker
57+
formatString="yyyy/MM/dd"
58+
value={this.state.value}
59+
onChange={this.handleChange}
60+
/>
61+
</div>
62+
)
63+
}
64+
}
65+
66+
export default DatePicker
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './DatePicker'

frontend/src/components/widgets/Time/index.tsx

Lines changed: 0 additions & 1 deletion
This file was deleted.

frontend/src/components/widgets/Time/Time.tsx renamed to frontend/src/components/widgets/TimePicker/TimePicker.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ interface State extends StState {
1919
value: Date;
2020
}
2121

22-
class Time extends PureStreamlitElement<Props, State> {
22+
class TimePicker extends PureStreamlitElement<Props, State> {
2323
public constructor(props: Props) {
2424
super(props)
2525

@@ -33,14 +33,6 @@ class Time extends PureStreamlitElement<Props, State> {
3333
this.props.widgetMgr.sendUpdateWidgetsMessage()
3434
}
3535

36-
private handleChange = (value: Date): void => {
37-
const widgetId = this.props.element.get('id')
38-
39-
this.setState({ value })
40-
this.props.widgetMgr.setStringValue(widgetId, this.dateToString(value))
41-
this.props.widgetMgr.sendUpdateWidgetsMessage()
42-
}
43-
4436
private stringToDate = (value: string): Date => {
4537
const [hours, minutes] = value.split(':').map(Number)
4638
const date = new Date()
@@ -55,6 +47,14 @@ class Time extends PureStreamlitElement<Props, State> {
5547
return hours + ':' + minutes
5648
}
5749

50+
private handleChange = (value: Date): void => {
51+
const widgetId = this.props.element.get('id')
52+
53+
this.setState({ value })
54+
this.props.widgetMgr.setStringValue(widgetId, this.dateToString(value))
55+
this.props.widgetMgr.sendUpdateWidgetsMessage()
56+
}
57+
5858
public safeRender(): React.ReactNode {
5959
const label = this.props.element.get('label')
6060
const style = { width: this.props.width }
@@ -72,4 +72,4 @@ class Time extends PureStreamlitElement<Props, State> {
7272
}
7373
}
7474

75-
export default Time
75+
export default TimePicker
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './TimePicker'

lib/streamlit/DeltaGenerator.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,14 @@ def time(self, element, ui_value, label, value=''):
12401240
element.time.value = current_value
12411241
return current_value
12421242

1243+
@_widget
1244+
def date(self, element, ui_value, label, value=''):
1245+
"""Date picker doc string."""
1246+
current_value = ui_value if ui_value is not None else value
1247+
element.date.label = label
1248+
element.date.value = current_value
1249+
return current_value
1250+
12431251
@_with_element
12441252
def progress(self, element, value):
12451253
"""Display a progress bar.

lib/streamlit/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ def wrapped_method(*args, **kwargs):
114114
checkbox = _with_dg(_DeltaGenerator.checkbox) # noqa: E221
115115
code = _with_dg(_DeltaGenerator.code) # noqa: E221
116116
dataframe = _with_dg(_DeltaGenerator.dataframe) # noqa: E221
117+
date = _with_dg(_DeltaGenerator.date) # noqa: E221
117118
deck_gl_chart = _with_dg(_DeltaGenerator.deck_gl_chart) # noqa: E221
118119
empty = _with_dg(_DeltaGenerator.empty) # noqa: E221
119120
error = _with_dg(_DeltaGenerator.error) # noqa: E221

protobuf/Date.proto

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
syntax = "proto3";
2+
3+
message Date {
4+
string id = 1;
5+
string label = 2;
6+
string value = 3;
7+
}

protobuf/Element.proto

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import "Button.proto";
77
import "Chart.proto";
88
import "Checkbox.proto";
99
import "DataFrame.proto";
10+
import "Date.proto";
1011
import "DeckGlChart.proto";
1112
import "DocString.proto";
1213
import "Empty.proto";
@@ -39,6 +40,7 @@ message Element {
3940
Checkbox checkbox = 20;
4041
DataFrame data_frame = 3;
4142
DataFrame table = 11;
43+
Date date = 27;
4244
DeckGlChart deck_gl_chart = 15;
4345
DocString doc_string = 7;
4446
Empty empty = 2;
@@ -58,6 +60,6 @@ message Element {
5860
VegaLiteChart vega_lite_chart = 10;
5961
Video video = 14;
6062

61-
// Next ID: 27
63+
// Next ID: 28
6264
}
6365
}

0 commit comments

Comments
 (0)