select.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. """A select component."""
  2. from typing import Any, Dict, List, Optional, Union
  3. from reflex.components.chakra import ChakraComponent, LiteralInputVariant
  4. from reflex.components.chakra.typography.text import Text
  5. from reflex.components.component import Component
  6. from reflex.components.core.foreach import Foreach
  7. from reflex.constants import EventTriggers
  8. from reflex.utils.types import _issubclass
  9. from reflex.vars import Var
  10. class Select(ChakraComponent):
  11. """Select component is a component that allows users pick a value from predefined options. Ideally, it should be used when there are more than 5 options, otherwise you might consider using a radio group instead."""
  12. tag = "Select"
  13. # State var to bind the select.
  14. value: Optional[Var[str]] = None
  15. # The default value of the select.
  16. default_value: Optional[Var[str]] = None
  17. # The placeholder text.
  18. placeholder: Optional[Var[str]] = None
  19. # The border color when the select is invalid.
  20. error_border_color: Optional[Var[str]] = None
  21. # The border color when the select is focused.
  22. focus_border_color: Optional[Var[str]] = None
  23. # If true, the select will be disabled.
  24. is_disabled: Optional[Var[bool]] = None
  25. # If true, the form control will be invalid. This has 2 side effects: - The FormLabel and FormErrorIcon will have `data-invalid` set to true - The form element (e.g, Input) will have `aria-invalid` set to true
  26. is_invalid: Optional[Var[bool]] = None
  27. # If true, the form control will be required. This has 2 side effects: - The FormLabel will show a required indicator - The form element (e.g, Input) will have `aria-required` set to true
  28. is_required: Optional[Var[bool]] = None
  29. # "outline" | "filled" | "flushed" | "unstyled"
  30. variant: Optional[Var[LiteralInputVariant]] = None
  31. # The size of the select.
  32. size: Optional[Var[str]] = None
  33. # The name of the form field
  34. name: Optional[Var[str]] = None
  35. def get_event_triggers(self) -> Dict[str, Union[Var, Any]]:
  36. """Get the event triggers that pass the component's value to the handler.
  37. Returns:
  38. A dict mapping the event trigger to the var that is passed to the handler.
  39. """
  40. return {
  41. **super().get_event_triggers(),
  42. EventTriggers.ON_CHANGE: lambda e0: [e0.target.value],
  43. }
  44. @classmethod
  45. def create(cls, *children, **props) -> Component:
  46. """Create a select component.
  47. If a list is provided as the first children, a default component
  48. will be created for each item in the list.
  49. Args:
  50. *children: The children of the component.
  51. **props: The props of the component.
  52. Returns:
  53. The component.
  54. """
  55. if len(children) == 1 and isinstance(children[0], list):
  56. children = [Option.create(child) for child in children[0]]
  57. if (
  58. len(children) == 1
  59. and isinstance(children[0], Var)
  60. and _issubclass(children[0]._var_type, List)
  61. ):
  62. children = [Foreach.create(children[0], lambda item: Option.create(item))]
  63. return super().create(*children, **props)
  64. class Option(Text):
  65. """A select option."""
  66. tag = "option"
  67. value: Optional[Var[Any]] = None
  68. @classmethod
  69. def create(cls, *children, **props) -> Component:
  70. """Create a select option component.
  71. By default, the value of the option is the text of the option.
  72. Args:
  73. *children: The children of the component.
  74. **props: The props of the component.
  75. Returns:
  76. The component.
  77. """
  78. if "value" not in props:
  79. assert len(children) == 1
  80. props["value"] = children[0]
  81. return super().create(*children, **props)