浏览代码

Add keypress event handlers (#523)

Nikhil Rao 2 年之前
父节点
当前提交
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.
         """
         # 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 isinstance(value, Var):
@@ -174,7 +175,7 @@ class Component(Base, ABC):
                 raise ValueError(f"Invalid event chain: {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 isinstance(value, EventHandler):
@@ -231,25 +232,16 @@ class Component(Base, ABC):
         Returns:
             The event triggers.
         """
-        return EVENT_TRIGGERS | cls.get_controlled_triggers()
+        return EVENT_TRIGGERS | set(cls.get_controlled_triggers())
 
     @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.
 
         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
     def get_alias(cls) -> Optional[str]:

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

@@ -1,6 +1,6 @@
 """A checkbox component."""
 
-from typing import Set
+from typing import Dict
 
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.libs.chakra import ChakraComponent
@@ -46,22 +46,15 @@ class Checkbox(ChakraComponent):
     spacing: Var[str]
 
     @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.
 
         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):

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

@@ -1,8 +1,9 @@
 """An editable component."""
 
-from typing import Set
+from typing import Dict
 
 from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 
 
@@ -36,17 +37,17 @@ class Editable(ChakraComponent):
     default_value: Var[str]
 
     @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.
 
         Returns:
-            The controlled event triggers.
+            A dict mapping the event trigger to the var that is passed to the handler.
         """
         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."""
 
-from typing import Set
+from typing import Dict
 
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.libs.chakra import ChakraComponent
@@ -49,22 +49,20 @@ class Input(ChakraComponent):
     size: Var[str]
 
     @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.
 
         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):

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

@@ -1,9 +1,10 @@
 """A number input component."""
 
-from typing import Set
+from typing import Dict
 
 from pynecone.components.component import Component
 from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 
 
@@ -64,13 +65,15 @@ class NumberInput(ChakraComponent):
     variant: Var[str]
 
     @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.
 
         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
     def create(cls, *children, **props) -> Component:

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

@@ -1,9 +1,10 @@
 """A pin input component."""
 
-from typing import Set
+from typing import Dict
 
 from pynecone.components.component import Component
 from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 
 
@@ -55,13 +56,16 @@ class PinInput(ChakraComponent):
     variant: Var[str]
 
     @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.
 
         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
     def create(cls, *children, **props) -> Component:

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

@@ -1,13 +1,14 @@
 """A radio component."""
 
 
-from typing import Any, List, Set
+from typing import Any, Dict, List
 
 from pynecone import utils
 from pynecone.components.component import Component
 from pynecone.components.layout.foreach import Foreach
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.typography.text import Text
+from pynecone.event import EVENT_ARG
 from pynecone.var import Var
 
 
@@ -20,13 +21,15 @@ class RadioGroup(ChakraComponent):
     value: Var[Any]
 
     @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.
 
         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
     def create(cls, *children, **props) -> Component:

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

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

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

@@ -1,6 +1,6 @@
 """A select component."""
 
-from typing import Any, List, Set
+from typing import Any, Dict, List
 
 from pynecone import utils
 from pynecone.components.component import EVENT_ARG, Component
@@ -46,22 +46,15 @@ class Select(ChakraComponent):
     variant: Var[str]
 
     @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.
 
         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
     def create(cls, *children, **props) -> Component:

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

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

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

@@ -1,5 +1,5 @@
 """A switch component."""
-from typing import Set
+from typing import Dict
 
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.libs.chakra import ChakraComponent
@@ -39,19 +39,12 @@ class Switch(ChakraComponent):
     placeholder: Var[str]
 
     @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.
 
         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."""
 
-from typing import Set
+from typing import Dict
 
 from pynecone.components.component import EVENT_ARG
 from pynecone.components.libs.chakra import ChakraComponent
@@ -43,19 +43,17 @@ class TextArea(ChakraComponent):
     variant: Var[str]
 
     @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.
 
         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."""
 
     target: Target = Target()
+    key: str = ""
 
 
 # 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
 
 from pynecone.components.component import Component, CustomComponent, ImportDict
 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.style import Style
 from pynecone.var import Var
@@ -61,13 +61,16 @@ def component2() -> Type[Component]:
         arr: Var[List[str]]
 
         @classmethod
-        def get_controlled_triggers(cls) -> Set[str]:
+        def get_controlled_triggers(cls) -> Dict[str, Var]:
             """Test controlled triggers.
 
             Returns:
                 Test controlled triggers.
             """
-            return {"on_open", "on_close"}
+            return {
+                "on_open": EVENT_ARG,
+                "on_close": EVENT_ARG,
+            }
 
         def _get_imports(self) -> ImportDict:
             return {"react-redux": {"connect"}}
@@ -269,8 +272,8 @@ def test_get_controlled_triggers(component1, component2):
         component1: 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):