Przeglądaj źródła

Add keypress event handlers (#523)

Nikhil Rao 2 lat temu
rodzic
commit
0bd8f6acfc

+ 7 - 15
pynecone/components/component.py

@@ -166,7 +166,8 @@ class Component(Base, ABC):
             ValueError: If the value is not a valid event chain.
             ValueError: If the value is not a valid event chain.
         """
         """
         # Check if the trigger is a controlled event.
         # Check if the trigger is a controlled event.
-        is_controlled_event = event_trigger in self.get_controlled_triggers()
+        controlled_triggers = self.get_controlled_triggers()
+        is_controlled_event = event_trigger in controlled_triggers
 
 
         # If it's an event chain var, return it.
         # If it's an event chain var, return it.
         if isinstance(value, Var):
         if isinstance(value, Var):
@@ -174,7 +175,7 @@ class Component(Base, ABC):
                 raise ValueError(f"Invalid event chain: {value}")
                 raise ValueError(f"Invalid event chain: {value}")
             return value
             return value
 
 
-        arg = self.get_controlled_value()
+        arg = controlled_triggers.get(event_trigger, EVENT_ARG)
 
 
         # If the input is a single event handler, wrap it in a list.
         # If the input is a single event handler, wrap it in a list.
         if isinstance(value, EventHandler):
         if isinstance(value, EventHandler):
@@ -231,25 +232,16 @@ class Component(Base, ABC):
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return EVENT_TRIGGERS | cls.get_controlled_triggers()
+        return EVENT_TRIGGERS | set(cls.get_controlled_triggers())
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        return set()
-
-    @classmethod
-    def get_controlled_value(cls) -> Var:
-        """Get the var that is passed to the event handler for controlled triggers.
-
-        Returns:
-            The controlled value.
-        """
-        return EVENT_ARG
+        return {}
 
 
     @classmethod
     @classmethod
     def get_alias(cls) -> Optional[str]:
     def get_alias(cls) -> Optional[str]:

+ 6 - 13
pynecone/components/forms/checkbox.py

@@ -1,6 +1,6 @@
 """A checkbox component."""
 """A checkbox component."""
 
 
-from typing import Set
+from typing import Dict
 
 
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
@@ -46,22 +46,15 @@ class Checkbox(ChakraComponent):
     spacing: Var[str]
     spacing: Var[str]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        return {"on_change"}
-
-    @classmethod
-    def get_controlled_value(cls) -> Var:
-        """Get the var that is passed to the event handler for controlled triggers.
-
-        Returns:
-            The controlled value.
-        """
-        return EVENT_ARG.target.checked
+        return {
+            "on_change": EVENT_ARG.target.checked,
+        }
 
 
 
 
 class CheckboxGroup(ChakraComponent):
 class CheckboxGroup(ChakraComponent):

+ 8 - 7
pynecone/components/forms/editable.py

@@ -1,8 +1,9 @@
 """An editable component."""
 """An editable component."""
 
 
-from typing import Set
+from typing import Dict
 
 
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 from pynecone.var import Var
 
 
 
 
@@ -36,17 +37,17 @@ class Editable(ChakraComponent):
     default_value: Var[str]
     default_value: Var[str]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change",
-            "on_edit",
-            "on_submit",
-            "on_cancel",
+            "on_change": EVENT_ARG,
+            "on_edit": EVENT_ARG,
+            "on_submit": EVENT_ARG,
+            "on_cancel": EVENT_ARG,
         }
         }
 
 
 
 

+ 11 - 13
pynecone/components/forms/input.py

@@ -1,6 +1,6 @@
 """An input component."""
 """An input component."""
 
 
-from typing import Set
+from typing import Dict
 
 
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
@@ -49,22 +49,20 @@ class Input(ChakraComponent):
     size: Var[str]
     size: Var[str]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        return {"on_change", "on_focus", "on_blur"}
-
-    @classmethod
-    def get_controlled_value(cls) -> Var:
-        """Get the var that is passed to the event handler for controlled triggers.
-
-        Returns:
-            The controlled value.
-        """
-        return EVENT_ARG.target.value
+        return {
+            "on_change": EVENT_ARG.target.value,
+            "on_focus": EVENT_ARG.target.value,
+            "on_blur": EVENT_ARG.target.value,
+            "on_key_down": EVENT_ARG.key,
+            "on_key_press": EVENT_ARG.key,
+            "on_key_up": EVENT_ARG.key,
+        }
 
 
 
 
 class InputGroup(ChakraComponent):
 class InputGroup(ChakraComponent):

+ 7 - 4
pynecone/components/forms/numberinput.py

@@ -1,9 +1,10 @@
 """A number input component."""
 """A number input component."""
 
 
-from typing import Set
+from typing import Dict
 
 
 from pynecone.components.component import Component
 from pynecone.components.component import Component
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 from pynecone.var import Var
 
 
 
 
@@ -64,13 +65,15 @@ class NumberInput(ChakraComponent):
     variant: Var[str]
     variant: Var[str]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        return {"on_change"}
+        return {
+            "on_change": EVENT_ARG,
+        }
 
 
     @classmethod
     @classmethod
     def create(cls, *children, **props) -> Component:
     def create(cls, *children, **props) -> Component:

+ 8 - 4
pynecone/components/forms/pininput.py

@@ -1,9 +1,10 @@
 """A pin input component."""
 """A pin input component."""
 
 
-from typing import Set
+from typing import Dict
 
 
 from pynecone.components.component import Component
 from pynecone.components.component import Component
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 from pynecone.var import Var
 
 
 
 
@@ -55,13 +56,16 @@ class PinInput(ChakraComponent):
     variant: Var[str]
     variant: Var[str]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        return {"on_change", "on_complete"}
+        return {
+            "on_change": EVENT_ARG,
+            "on_complete": EVENT_ARG,
+        }
 
 
     @classmethod
     @classmethod
     def create(cls, *children, **props) -> Component:
     def create(cls, *children, **props) -> Component:

+ 7 - 4
pynecone/components/forms/radio.py

@@ -1,13 +1,14 @@
 """A radio component."""
 """A radio component."""
 
 
 
 
-from typing import Any, List, Set
+from typing import Any, Dict, List
 
 
 from pynecone import utils
 from pynecone import utils
 from pynecone.components.component import Component
 from pynecone.components.component import Component
 from pynecone.components.layout.foreach import Foreach
 from pynecone.components.layout.foreach import Foreach
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.typography.text import Text
 from pynecone.components.typography.text import Text
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 from pynecone.var import Var
 
 
 
 
@@ -20,13 +21,15 @@ class RadioGroup(ChakraComponent):
     value: Var[Any]
     value: Var[Any]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        return {"on_change"}
+        return {
+            "on_change": EVENT_ARG,
+        }
 
 
     @classmethod
     @classmethod
     def create(cls, *children, **props) -> Component:
     def create(cls, *children, **props) -> Component:

+ 7 - 6
pynecone/components/forms/rangeslider.py

@@ -1,9 +1,10 @@
 """A range slider component."""
 """A range slider component."""
 
 
-from typing import List, Set
+from typing import Dict, List
 
 
 from pynecone.components.component import Component
 from pynecone.components.component import Component
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 from pynecone.var import Var
 
 
 
 
@@ -43,16 +44,16 @@ class RangeSlider(ChakraComponent):
     min_steps_between_thumbs: Var[int]
     min_steps_between_thumbs: Var[int]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change",
-            "on_change_end",
-            "on_change_start",
+            "on_change": EVENT_ARG,
+            "on_change_end": EVENT_ARG,
+            "on_change_start": EVENT_ARG,
         }
         }
 
 
     @classmethod
     @classmethod

+ 6 - 13
pynecone/components/forms/select.py

@@ -1,6 +1,6 @@
 """A select component."""
 """A select component."""
 
 
-from typing import Any, List, Set
+from typing import Any, Dict, List
 
 
 from pynecone import utils
 from pynecone import utils
 from pynecone.components.component import EVENT_ARG, Component
 from pynecone.components.component import EVENT_ARG, Component
@@ -46,22 +46,15 @@ class Select(ChakraComponent):
     variant: Var[str]
     variant: Var[str]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        return {"on_change"}
-
-    @classmethod
-    def get_controlled_value(cls) -> Var:
-        """Get the var that is passed to the event handler for controlled triggers.
-
-        Returns:
-            The controlled value.
-        """
-        return EVENT_ARG.target.value
+        return {
+            "on_change": EVENT_ARG.target.value,
+        }
 
 
     @classmethod
     @classmethod
     def create(cls, *children, **props) -> Component:
     def create(cls, *children, **props) -> Component:

+ 7 - 6
pynecone/components/forms/slider.py

@@ -1,9 +1,10 @@
 """A slider component."""
 """A slider component."""
 
 
-from typing import Set
+from typing import Dict
 
 
 from pynecone.components.component import Component
 from pynecone.components.component import Component
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 from pynecone.var import Var
 
 
 
 
@@ -43,16 +44,16 @@ class Slider(ChakraComponent):
     min_steps_between_thumbs: Var[int]
     min_steps_between_thumbs: Var[int]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change",
-            "on_change_end",
-            "on_change_start",
+            "on_change": EVENT_ARG,
+            "on_change_end": EVENT_ARG,
+            "on_change_start": EVENT_ARG,
         }
         }
 
 
     @classmethod
     @classmethod

+ 6 - 13
pynecone/components/forms/switch.py

@@ -1,5 +1,5 @@
 """A switch component."""
 """A switch component."""
-from typing import Set
+from typing import Dict
 
 
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
@@ -39,19 +39,12 @@ class Switch(ChakraComponent):
     placeholder: Var[str]
     placeholder: Var[str]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        return {"on_change"}
-
-    @classmethod
-    def get_controlled_value(cls) -> Var:
-        """Get the var that is passed to the event handler for controlled triggers.
-
-        Returns:
-            The controlled value.
-        """
-        return EVENT_ARG.target.checked
+        return {
+            "on_change": EVENT_ARG.target.checked,
+        }

+ 11 - 13
pynecone/components/forms/textarea.py

@@ -1,6 +1,6 @@
 """A textarea component."""
 """A textarea component."""
 
 
-from typing import Set
+from typing import Dict
 
 
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
@@ -43,19 +43,17 @@ class TextArea(ChakraComponent):
     variant: Var[str]
     variant: Var[str]
 
 
     @classmethod
     @classmethod
-    def get_controlled_triggers(cls) -> Set[str]:
+    def get_controlled_triggers(cls) -> Dict[str, Var]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        return {"on_change", "on_focus", "on_blur"}
-
-    @classmethod
-    def get_controlled_value(cls) -> Var:
-        """Get the var that is passed to the event handler for controlled triggers.
-
-        Returns:
-            The controlled value.
-        """
-        return EVENT_ARG.target.value
+        return {
+            "on_change": EVENT_ARG.target.value,
+            "on_focus": EVENT_ARG.target.value,
+            "on_blur": EVENT_ARG.target.value,
+            "on_key_down": EVENT_ARG.key,
+            "on_key_press": EVENT_ARG.key,
+            "on_key_up": EVENT_ARG.key,
+        }

+ 1 - 0
pynecone/event.py

@@ -115,6 +115,7 @@ class FrontendEvent(Base):
     """A Javascript event."""
     """A Javascript event."""
 
 
     target: Target = Target()
     target: Target = Target()
+    key: str = ""
 
 
 
 
 # The default event argument.
 # The default event argument.

+ 9 - 6
tests/components/test_component.py

@@ -1,10 +1,10 @@
-from typing import List, Set, Type
+from typing import Dict, List, Type
 
 
 import pytest
 import pytest
 
 
 from pynecone.components.component import Component, CustomComponent, ImportDict
 from pynecone.components.component import Component, CustomComponent, ImportDict
 from pynecone.components.layout.box import Box
 from pynecone.components.layout.box import Box
-from pynecone.event import EVENT_TRIGGERS, EventHandler
+from pynecone.event import EVENT_ARG, EVENT_TRIGGERS, EventHandler
 from pynecone.state import State
 from pynecone.state import State
 from pynecone.style import Style
 from pynecone.style import Style
 from pynecone.var import Var
 from pynecone.var import Var
@@ -61,13 +61,16 @@ def component2() -> Type[Component]:
         arr: Var[List[str]]
         arr: Var[List[str]]
 
 
         @classmethod
         @classmethod
-        def get_controlled_triggers(cls) -> Set[str]:
+        def get_controlled_triggers(cls) -> Dict[str, Var]:
             """Test controlled triggers.
             """Test controlled triggers.
 
 
             Returns:
             Returns:
                 Test controlled triggers.
                 Test controlled triggers.
             """
             """
-            return {"on_open", "on_close"}
+            return {
+                "on_open": EVENT_ARG,
+                "on_close": EVENT_ARG,
+            }
 
 
         def _get_imports(self) -> ImportDict:
         def _get_imports(self) -> ImportDict:
             return {"react-redux": {"connect"}}
             return {"react-redux": {"connect"}}
@@ -269,8 +272,8 @@ def test_get_controlled_triggers(component1, component2):
         component1: A test component.
         component1: A test component.
         component2: A test component.
         component2: A test component.
     """
     """
-    assert component1.get_controlled_triggers() == set()
-    assert component2.get_controlled_triggers() == {"on_open", "on_close"}
+    assert component1.get_controlled_triggers() == dict()
+    assert set(component2.get_controlled_triggers()) == {"on_open", "on_close"}
 
 
 
 
 def test_get_triggers(component1, component2):
 def test_get_triggers(component1, component2):