-
-
Notifications
You must be signed in to change notification settings - Fork 687
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added the dateinput and timeinput widgets for toga/web #2176
base: main
Are you sure you want to change the base?
Changes from all commits
5f9362f
e06a1d8
0ebfe94
2d6a61d
8e915a5
e893f3b
84d80fd
308cc1e
6c1d45b
b52bc7a
191d6e7
7fc20d1
df9d70e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
DateInput and TimeInput widgets were added to the Web backend. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import datetime | ||
|
||
from toga_web.libs import create_proxy | ||
|
||
from .base import Widget | ||
|
||
|
||
def py_date(native_date): | ||
return datetime.datetime.strptime(native_date, "%Y-%m-%d").date() | ||
|
||
|
||
def native_date(py_date): | ||
return py_date.strftime("%Y-%m-%d") | ||
|
||
|
||
class DateInput(Widget): | ||
def create(self): | ||
self._return_listener = None | ||
self.native = self._create_native_widget("sl-input") | ||
self.native.setAttribute("type", "date") | ||
self.native.addEventListener("sl-change", create_proxy(self.on_change)) | ||
|
||
def get_value(self): | ||
return py_date(self.native.value) | ||
|
||
def set_value(self, value): | ||
if value is None: | ||
self.native.value = "" | ||
self.native.value = value | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't appear to be fully working with initial values. In my testing, on Safari, the current date is being displayed on every date widget in the example app; on Chrome (on macOS), I get dd/mm/yyyy as the default values. The "with max" and "with min and max" date examples should have an initial date of 2021-04-02; "any" and "with min" should have no initial value (although if the browser defaults to the current date as a browser behavior, that's fine). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if this is impacting the behavior difference - but I'm using AU date formatting order, so I see "6/11/2023" as todays' date (6 Nov 2023). I'm not sure the extent to which browsers will be rejecting the default value of "%Y-%m-%d" on the basis of localised validation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I only tested this on chrome, I'll test this on firefox as well to see the differences (my apologies).
but I'll definitely change this piece to have this functionality. |
||
|
||
def on_change(self, event): | ||
self.interface.on_change(None) | ||
|
||
def get_min_date(self): | ||
if self.native.min: | ||
return py_date(self.native.min) | ||
return datetime.date(1800, 1, 1) | ||
|
||
def get_max_date(self): | ||
if self.native.max: | ||
return py_date(self.native.max) | ||
return datetime.date(8999, 12, 31) | ||
|
||
def set_min_date(self, value): | ||
self.native.min = native_date(value) | ||
|
||
def set_max_date(self, value): | ||
self.native.max = native_date(value) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import datetime | ||
|
||
from toga_web.libs import create_proxy | ||
|
||
from .base import Widget | ||
|
||
|
||
def py_time(native_time): | ||
return datetime.time.fromisoformat(native_time) | ||
|
||
|
||
def native_time(py_time): | ||
return py_time.strftime("%H:%M") | ||
|
||
|
||
class TimeInput(Widget): | ||
def create(self): | ||
self._return_listener = None | ||
self.native = self._create_native_widget("sl-input") | ||
self.native.setAttribute("type", "time") | ||
|
||
self.set_value(datetime.datetime.now().time().strftime("%H:%M")) | ||
self.native.addEventListener("sl-change", create_proxy(self.on_change)) | ||
|
||
def on_change(self, event): | ||
self.interface.on_change(None) | ||
|
||
def get_value(self): | ||
return py_time(self.native.value) | ||
|
||
def set_value(self, value): | ||
if value is None: | ||
self.native.value = "" | ||
self.native.value = self._format_time(value) | ||
|
||
def set_min_time(self, value): | ||
self.native.min = self._format_time(value) | ||
|
||
def set_max_time(self, value): | ||
self.native.max = self._format_time(value) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These min/max values don't appear to be applied - I can set times before the min/after the max in the example app. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd love to know the way you'd like this handled, the way I'm thinking is to essentially set the value for that time to the minimum or maximum (which ever is relevant). The only thing here is that browsers don't enforce a min/max on the time input and I couldn't find the max/min on the shoelace components. I'm certainly open to anything here but I think it might be a bit hidden if we set the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, Android has a similar limitation. The approach we've taken there is to catch the "on change" event, and when it occurs, explicitly use the API to set the value of the widget to the value that was just set. This might seems like a no-op, but it has the effect of clipping the time to the min/max bounds. |
||
|
||
def get_min_time(self): | ||
if self.native.min: | ||
return py_time(self.native.min) | ||
return datetime.time(0, 0, 0) | ||
|
||
def get_max_time(self): | ||
if self.native.max: | ||
return py_time(self.native.max) | ||
return datetime.time(23, 59, 59) | ||
|
||
def _format_time(self, value): | ||
if isinstance(value, str): | ||
value = native_time(py_time(value)) | ||
if isinstance(value, datetime.time): | ||
value = native_time(value) | ||
return value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TimeInput will also need to be updated.