From 84858854ae2bc4a5b3b136e04b65b44fef26ebab Mon Sep 17 00:00:00 2001 From: Martin Xu <15661672+martinxu9@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:07:27 -0800 Subject: [PATCH] Clean up Radix Form component (#2423) * form pr * cleanup * pyi --- reflex/components/radix/primitives/form.py | 35 +++++++++++++++++++-- reflex/components/radix/primitives/form.pyi | 24 ++++++++------ reflex/constants/event.py | 1 + 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/reflex/components/radix/primitives/form.py b/reflex/components/radix/primitives/form.py index 561d161a3..c6d95864e 100644 --- a/reflex/components/radix/primitives/form.py +++ b/reflex/components/radix/primitives/form.py @@ -8,6 +8,7 @@ from typing import Any, Dict, Iterator, Literal from jinja2 import Environment from reflex.components.component import Component +from reflex.components.radix.themes.components.textfield import TextFieldInput from reflex.components.tags.tag import Tag from reflex.constants.base import Dirs from reflex.constants.event import EventTriggers @@ -52,7 +53,7 @@ class FormRoot(FormComponent): # If true, the form will be cleared after submit. reset_on_submit: Var[bool] = False # type: ignore - # The name used to make this form's submit handler function unique + # The name used to make this form's submit handler function unique. handle_submit_unique_name: Var[str] def get_event_triggers(self) -> Dict[str, Any]: @@ -64,7 +65,7 @@ class FormRoot(FormComponent): return { **super().get_event_triggers(), EventTriggers.ON_SUBMIT: lambda e0: [FORM_DATA], - "on_clear_server_errors": lambda: [], + EventTriggers.ON_CLEAR_SERVER_ERRORS: lambda: [], } @classmethod @@ -171,8 +172,10 @@ class FormField(FormComponent): alias = "RadixFormField" + # The name of the form field, that is passed down to the control and used to match with validation messages. name: Var[str] + # Flag to mark the form field as invalid, for server side validation. server_invalid: Var[bool] def _apply_theme(self, theme: Component | None): @@ -206,6 +209,32 @@ class FormControl(FormComponent): alias = "RadixFormControl" + @classmethod + def create(cls, *children, **props): + """Create a Form Control component. + + Args: + *children: The children of the form. + **props: The properties of the form. + + Raises: + ValueError: If the number of children is greater than 1. + TypeError: If a child exists but it is not a TextFieldInput. + + Returns: + The form control component. + """ + if len(children) > 1: + raise ValueError( + f"FormControl can only have at most one child, got {len(children)} children" + ) + for child in children: + if not isinstance(child, TextFieldInput): + raise TypeError( + "Only Radix TextFieldInput is allowed as child of FormControl" + ) + return super().create(*children, **props) + LiteralMatcher = Literal[ "badInput", @@ -235,7 +264,7 @@ class FormMessage(FormComponent): match: Var[LiteralMatcher] # Forces the message to be shown. This is useful when using server-side validation. - forceMatch: Var[bool] + force_match: Var[bool] def _apply_theme(self, theme: Component | None): return { diff --git a/reflex/components/radix/primitives/form.pyi b/reflex/components/radix/primitives/form.pyi index 208aab410..0a11250a1 100644 --- a/reflex/components/radix/primitives/form.pyi +++ b/reflex/components/radix/primitives/form.pyi @@ -11,6 +11,7 @@ from hashlib import md5 from typing import Any, Dict, Iterator, Literal from jinja2 import Environment from reflex.components.component import Component +from reflex.components.radix.themes.components.textfield import TextFieldInput from reflex.components.tags.tag import Tag from reflex.constants.base import Dirs from reflex.constants.event import EventTriggers @@ -180,7 +181,7 @@ class FormRoot(FormComponent): Args: *children: The children of the form. reset_on_submit: If true, the form will be cleared after submit. - handle_submit_unique_name: The name used to make this form's submit handler function unique + handle_submit_unique_name: The name used to make this form's submit handler function unique. as_child: Change the default rendered element for the one passed as a child. style: The style of the component. key: A unique key for the component. @@ -261,6 +262,8 @@ class FormField(FormComponent): Args: *children: The children of the component. + name: The name of the form field, that is passed down to the control and used to match with validation messages. + server_invalid: Flag to mark the form field as invalid, for server side validation. as_child: Change the default rendered element for the one passed as a child. style: The style of the component. key: A unique key for the component. @@ -419,10 +422,10 @@ class FormControl(FormComponent): ] = None, **props ) -> "FormControl": - """Create the component. + """Create a Form Control component. Args: - *children: The children of the component. + *children: The children of the form. as_child: Change the default rendered element for the one passed as a child. style: The style of the component. key: A unique key for the component. @@ -430,13 +433,14 @@ class FormControl(FormComponent): class_name: The class name for the component. autofocus: Whether the component should take the focus once the page is loaded custom_attrs: custom attribute - **props: The props of the component. - - Returns: - The component. + **props: The properties of the form. Raises: - TypeError: If an invalid child is passed. + ValueError: If the number of children is greater than 1. + TypeError: If a child exists but it is not a TextFieldInput. + + Returns: + The form control component. """ ... @@ -490,7 +494,7 @@ class FormMessage(FormComponent): ], ] ] = None, - forceMatch: Optional[Union[Var[bool], bool]] = None, + force_match: Optional[Union[Var[bool], bool]] = None, as_child: Optional[Union[Var[bool], bool]] = None, style: Optional[Style] = None, key: Optional[Any] = None, @@ -551,7 +555,7 @@ class FormMessage(FormComponent): *children: The children of the component. name: Used to target a specific field by name when rendering outside of a Field part. match: Used to indicate on which condition the message should be visible. - forceMatch: Forces the message to be shown. This is useful when using server-side validation. + force_match: Forces the message to be shown. This is useful when using server-side validation. as_child: Change the default rendered element for the one passed as a child. style: The style of the component. key: A unique key for the component. diff --git a/reflex/constants/event.py b/reflex/constants/event.py index b62bc0d9e..d54ea4340 100644 --- a/reflex/constants/event.py +++ b/reflex/constants/event.py @@ -84,3 +84,4 @@ class EventTriggers(SimpleNamespace): ON_SUBMIT = "on_submit" ON_MOUNT = "on_mount" ON_UNMOUNT = "on_unmount" + ON_CLEAR_SERVER_ERRORS = "on_clear_server_errors"