select.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. """A select component."""
  2. from typing import Any, Dict, List
  3. from reflex.components.component import EVENT_ARG, Component
  4. from reflex.components.layout.foreach import Foreach
  5. from reflex.components.libs.chakra import ChakraComponent
  6. from reflex.components.typography.text import Text
  7. from reflex.utils import types
  8. from reflex.vars import Var
  9. class Select(ChakraComponent):
  10. """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."""
  11. tag = "Select"
  12. # State var to bind the select.
  13. value: Var[str]
  14. # The default value of the select.
  15. default_value: Var[str]
  16. # The placeholder text.
  17. placeholder: Var[str]
  18. # The border color when the select is invalid.
  19. error_border_color: Var[str]
  20. # The border color when the select is focused.
  21. focus_border_color: Var[str]
  22. # If true, the select will be disabled.
  23. is_disabled: Var[bool]
  24. # 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
  25. is_invalid: Var[bool]
  26. # If true, the form control will be readonly
  27. is_read_only: Var[bool]
  28. # 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
  29. is_required: Var[bool]
  30. # "outline" | "filled" | "flushed" | "unstyled"
  31. variant: Var[str]
  32. # The size of the select.
  33. size: Var[str]
  34. @classmethod
  35. def get_controlled_triggers(cls) -> Dict[str, Var]:
  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. "on_change": EVENT_ARG.target.value,
  42. }
  43. @classmethod
  44. def create(cls, *children, **props) -> Component:
  45. """Create a select component.
  46. If a list is provided as the first children, a default component
  47. will be created for each item in the list.
  48. Args:
  49. *children: The children of the component.
  50. **props: The props of the component.
  51. Returns:
  52. The component.
  53. """
  54. if len(children) == 1 and isinstance(children[0], list):
  55. children = [Option.create(child) for child in children[0]]
  56. if (
  57. len(children) == 1
  58. and isinstance(children[0], Var)
  59. and types._issubclass(children[0].type_, List)
  60. ):
  61. children = [Foreach.create(children[0], lambda item: Option.create(item))]
  62. return super().create(*children, **props)
  63. class Option(Text):
  64. """A select option."""
  65. tag = "option"
  66. value: Var[Any]
  67. @classmethod
  68. def create(cls, *children, **props) -> Component:
  69. """Create a select option component.
  70. By default, the value of the option is the text of the option.
  71. Args:
  72. *children: The children of the component.
  73. **props: The props of the component.
  74. Returns:
  75. The component.
  76. """
  77. if "value" not in props:
  78. assert len(children) == 1
  79. props["value"] = children[0]
  80. return super().create(*children, **props)