From 9485127c1cd86a871c013958790e30fe4f18aa4b Mon Sep 17 00:00:00 2001 From: Nikhil Rao Date: Fri, 26 May 2023 10:50:16 -0700 Subject: [PATCH] Handle multi-select (#1082) --- pynecone/components/component.py | 14 ++++++++++++++ pynecone/components/forms/select.py | 21 +++++++++++++++++---- pyproject.toml | 2 +- tests/components/forms/test_uploads.py | 14 +++++++------- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/pynecone/components/component.py b/pynecone/components/component.py index ccdce8e08..681ed145e 100644 --- a/pynecone/components/component.py +++ b/pynecone/components/component.py @@ -104,6 +104,11 @@ class Component(Base, ABC): initial_kwargs = { "id": kwargs.get("id"), "children": kwargs.get("children", []), + **{ + prop: Var.create(kwargs[prop]) + for prop in self.get_initial_props() + if prop in kwargs + }, } super().__init__(**initial_kwargs) @@ -343,6 +348,15 @@ class Component(Base, ABC): """ return set(cls.get_fields()) - set(Component.get_fields()) + @classmethod + def get_initial_props(cls) -> Set[str]: + """Get the initial props to set for the component. + + Returns: + The initial props to set. + """ + return set() + @classmethod def create(cls, *children, **props) -> Component: """Create the component. diff --git a/pynecone/components/forms/select.py b/pynecone/components/forms/select.py index 42aef7d87..328c4f1fe 100644 --- a/pynecone/components/forms/select.py +++ b/pynecone/components/forms/select.py @@ -1,6 +1,6 @@ """Provides a feature-rich Select and some (not all) related components.""" -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Set, Union from pynecone.base import Base from pynecone.components.component import Component @@ -304,9 +304,22 @@ class Select(Component): Returns: A dict mapping the event trigger to the var that is passed to the handler. """ - return { - "on_change": EVENT_ARG.value, - } + # A normal select returns the value. + value = EVENT_ARG.value + + # Multi-select returns a list of values. + if self.is_multi: + value = Var.create_safe(f"{EVENT_ARG}.map(e => e.value)", is_local=True) + return {"on_change": value} + + @classmethod + def get_initial_props(cls) -> Set[str]: + """Get the initial props to set for the component. + + Returns: + The initial props to set. + """ + return super().get_initial_props() | {"is_multi"} @classmethod def create( diff --git a/pyproject.toml b/pyproject.toml index 654c5c95d..f0b93fdf4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pynecone" -version = "0.1.31" +version = "0.1.32" description = "Web apps in pure Python." license = "Apache-2.0" authors = [ diff --git a/tests/components/forms/test_uploads.py b/tests/components/forms/test_uploads.py index c71f57136..bd70a1e30 100644 --- a/tests/components/forms/test_uploads.py +++ b/tests/components/forms/test_uploads.py @@ -47,18 +47,18 @@ def test_upload_component_render(upload_component): Args: upload_component: component fixture """ - uplaod = upload_component.render() + upload = upload_component.render() # upload - assert uplaod["name"] == "ReactDropzone" - assert uplaod["props"] == [ + assert upload["name"] == "ReactDropzone" + assert upload["props"] == [ "multiple={true}", "onDrop={e => File(e)}", ] - assert uplaod["args"] == ("getRootProps", "getInputProps") + assert upload["args"] == ("getRootProps", "getInputProps") # box inside of upload - [box] = uplaod["children"] + [box] = upload["children"] assert box["name"] == "Box" assert box["props"] == [ 'sx={{"border": "1px dotted black"}}', @@ -86,9 +86,9 @@ def test_upload_component_with_props_render(upload_component_with_props): Args: upload_component_with_props: component fixture """ - uplaod = upload_component_with_props.render() + upload = upload_component_with_props.render() - assert uplaod["props"] == [ + assert upload["props"] == [ "maxFiles={2}", "multiple={true}", "noDrag={true}",