cond.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. """Create a list of components from an iterable."""
  2. from __future__ import annotations
  3. from typing import Any, Optional
  4. from pynecone import utils
  5. from pynecone.components.component import Component
  6. from pynecone.components.layout.fragment import Fragment
  7. from pynecone.components.tags import CondTag, Tag
  8. from pynecone.var import Var
  9. class Cond(Component):
  10. """Render one of two components based on a condition."""
  11. # The cond to determine which component to render.
  12. cond: Var[Any]
  13. # The component to render if the cond is true.
  14. comp1: Component
  15. # The component to render if the cond is false.
  16. comp2: Component
  17. # Whether the cond is within another cond.
  18. is_nested: bool = False
  19. @classmethod
  20. def create(
  21. cls, cond: Var, comp1: Component, comp2: Optional[Component] = None
  22. ) -> Cond:
  23. """Create a conditional component.
  24. Args:
  25. cond: The cond to determine which component to render.
  26. comp1: The component to render if the cond is true.
  27. comp2: The component to render if the cond is false.
  28. Returns:
  29. The conditional component.
  30. """
  31. from pynecone.components.layout.foreach import Foreach
  32. if comp2 is None:
  33. comp2 = Fragment.create()
  34. if isinstance(comp1, Foreach):
  35. comp1 = Fragment.create(comp1)
  36. if isinstance(comp2, Foreach):
  37. comp2 = Fragment.create(comp2)
  38. if isinstance(comp1, Cond):
  39. comp1.is_nested = True
  40. if isinstance(comp2, Cond):
  41. comp2.is_nested = True
  42. return cls(
  43. cond=cond,
  44. comp1=comp1,
  45. comp2=comp2,
  46. children=[comp1, comp2],
  47. ) # type: ignore
  48. def _render(self) -> Tag:
  49. return CondTag(
  50. cond=self.cond,
  51. true_value=self.comp1.render(),
  52. false_value=self.comp2.render(),
  53. is_nested=self.is_nested,
  54. )
  55. def cond(condition: Any, c1: Any, c2: Any = None):
  56. """Create a conditional component or Prop.
  57. Args:
  58. condition: The cond to determine which component to render.
  59. c1: The component or prop to render if the cond_var is true.
  60. c2: The component or prop to render if the cond_var is false.
  61. Returns:
  62. The conditional component.
  63. Raises:
  64. ValueError: If the arguments are invalid.
  65. """
  66. # Import here to avoid circular imports.
  67. from pynecone.var import BaseVar, Var
  68. # Convert the condition to a Var.
  69. cond_var = Var.create(condition)
  70. assert cond_var is not None, "The condition must be set."
  71. # If the first component is a component, create a Cond component.
  72. if isinstance(c1, Component):
  73. assert c2 is None or isinstance(
  74. c2, Component
  75. ), "Both arguments must be components."
  76. return Cond.create(cond_var, c1, c2)
  77. # Otherwise, create a conditionl Var.
  78. # Check that the second argument is valid.
  79. if isinstance(c2, Component):
  80. raise ValueError("Both arguments must be props.")
  81. if c2 is None:
  82. raise ValueError("For conditional vars, the second argument must be set.")
  83. # Create the conditional var.
  84. return BaseVar(
  85. name=utils.format_cond(
  86. cond=cond_var.full_name,
  87. true_value=c1,
  88. false_value=c2,
  89. is_prop=True,
  90. ),
  91. type_=c1.type_ if isinstance(c1, BaseVar) else type(c1),
  92. )