diff --git a/pynecone/components/__init__.py b/pynecone/components/__init__.py index 4936e05fb..cf34bcb6b 100644 --- a/pynecone/components/__init__.py +++ b/pynecone/components/__init__.py @@ -1,10 +1,6 @@ """Import all the components.""" from __future__ import annotations -from typing import TYPE_CHECKING - -from pynecone import utils - from .component import Component from .datadisplay import * from .disclosure import * @@ -17,9 +13,6 @@ from .navigation import * from .overlay import * from .typography import * -if TYPE_CHECKING: - from typing import Any - # Add the convenience methods for all the components. # locals().update( # { @@ -29,6 +22,8 @@ if TYPE_CHECKING: # } # ) +# Add the convenience methods for all the components manually. +# This is necessary for static type checking to work. component = Component.create badge = Badge.create code = Code.create @@ -205,116 +200,3 @@ heading = Heading.create markdown = Markdown.create span = Span.create text = Text.create - - -# Add responsive styles shortcuts. -def mobile_only(*children, **props): - """Create a component that is only visible on mobile. - - Args: - *children: The children to pass to the component. - **props: The props to pass to the component. - - Returns: - The component. - """ - return Box.create(*children, **props, display=["block", "none", "none", "none"]) - - -def tablet_only(*children, **props): - """Create a component that is only visible on tablet. - - Args: - *children: The children to pass to the component. - **props: The props to pass to the component. - - Returns: - The component. - """ - return Box.create(*children, **props, display=["none", "block", "block", "none"]) - - -def desktop_only(*children, **props): - """Create a component that is only visible on desktop. - - Args: - *children: The children to pass to the component. - **props: The props to pass to the component. - - Returns: - The component. - """ - return Box.create(*children, **props, display=["none", "none", "none", "block"]) - - -def tablet_and_desktop(*children, **props): - """Create a component that is only visible on tablet and desktop. - - Args: - *children: The children to pass to the component. - **props: The props to pass to the component. - - Returns: - The component. - """ - return Box.create(*children, **props, display=["none", "block", "block", "block"]) - - -def mobile_and_tablet(*children, **props): - """Create a component that is only visible on mobile and tablet. - - Args: - *children: The children to pass to the component. - **props: The props to pass to the component. - - Returns: - The component. - """ - return Box.create(*children, **props, display=["block", "block", "block", "none"]) - - -def cond(condition: Any, c1: Any, c2: Any = None): - """Create a conditional component or Prop. - - Args: - condition: The cond to determine which component to render. - c1: The component or prop to render if the cond_var is true. - c2: The component or prop to render if the cond_var is false. - - Returns: - The conditional component. - - Raises: - ValueError: If the arguments are invalid. - """ - # Import here to avoid circular imports. - from pynecone.var import BaseVar, Var - - # Convert the condition to a Var. - cond_var = Var.create(condition) - assert cond_var is not None, "The condition must be set." - - # If the first component is a component, create a Cond component. - if isinstance(c1, Component): - assert c2 is None or isinstance( - c2, Component - ), "Both arguments must be components." - return Cond.create(cond_var, c1, c2) - - # Otherwise, create a conditionl Var. - # Check that the second argument is valid. - if isinstance(c2, Component): - raise ValueError("Both arguments must be props.") - if c2 is None: - raise ValueError("For conditional vars, the second argument must be set.") - - # Create the conditional var. - return BaseVar( - name=utils.format_cond( - cond=cond_var.full_name, - true_value=c1, - false_value=c2, - is_prop=True, - ), - type_=c1.type_ if isinstance(c1, BaseVar) else type(c1), - ) diff --git a/pynecone/components/layout/__init__.py b/pynecone/components/layout/__init__.py index 5c62768f9..e29550588 100644 --- a/pynecone/components/layout/__init__.py +++ b/pynecone/components/layout/__init__.py @@ -2,13 +2,20 @@ from .box import Box from .center import Center, Circle, Square -from .cond import Cond +from .cond import Cond, cond from .container import Container from .flex import Flex from .foreach import Foreach from .fragment import Fragment from .grid import Grid, GridItem, ResponsiveGrid from .html import Html +from .responsive import ( + desktop_only, + mobile_and_tablet, + mobile_only, + tablet_and_desktop, + tablet_only, +) from .spacer import Spacer from .stack import Hstack, Stack, Vstack from .wrap import Wrap, WrapItem diff --git a/pynecone/components/layout/cond.py b/pynecone/components/layout/cond.py index a77b6aaa0..b6f24de15 100644 --- a/pynecone/components/layout/cond.py +++ b/pynecone/components/layout/cond.py @@ -3,6 +3,7 @@ from __future__ import annotations from typing import Any, Optional +from pynecone import utils from pynecone.components.component import Component from pynecone.components.layout.fragment import Fragment from pynecone.components.tags import CondTag, Tag @@ -64,3 +65,50 @@ class Cond(Component): false_value=self.comp2.render(), is_nested=self.is_nested, ) + + +def cond(condition: Any, c1: Any, c2: Any = None): + """Create a conditional component or Prop. + + Args: + condition: The cond to determine which component to render. + c1: The component or prop to render if the cond_var is true. + c2: The component or prop to render if the cond_var is false. + + Returns: + The conditional component. + + Raises: + ValueError: If the arguments are invalid. + """ + # Import here to avoid circular imports. + from pynecone.var import BaseVar, Var + + # Convert the condition to a Var. + cond_var = Var.create(condition) + assert cond_var is not None, "The condition must be set." + + # If the first component is a component, create a Cond component. + if isinstance(c1, Component): + assert c2 is None or isinstance( + c2, Component + ), "Both arguments must be components." + return Cond.create(cond_var, c1, c2) + + # Otherwise, create a conditionl Var. + # Check that the second argument is valid. + if isinstance(c2, Component): + raise ValueError("Both arguments must be props.") + if c2 is None: + raise ValueError("For conditional vars, the second argument must be set.") + + # Create the conditional var. + return BaseVar( + name=utils.format_cond( + cond=cond_var.full_name, + true_value=c1, + false_value=c2, + is_prop=True, + ), + type_=c1.type_ if isinstance(c1, BaseVar) else type(c1), + ) diff --git a/pynecone/components/layout/responsive.py b/pynecone/components/layout/responsive.py new file mode 100644 index 000000000..324f9052d --- /dev/null +++ b/pynecone/components/layout/responsive.py @@ -0,0 +1,69 @@ +"""Responsive components.""" + +from pynecone.components.layout.box import Box + + +# Add responsive styles shortcuts. +def mobile_only(*children, **props): + """Create a component that is only visible on mobile. + + Args: + *children: The children to pass to the component. + **props: The props to pass to the component. + + Returns: + The component. + """ + return Box.create(*children, **props, display=["block", "none", "none", "none"]) + + +def tablet_only(*children, **props): + """Create a component that is only visible on tablet. + + Args: + *children: The children to pass to the component. + **props: The props to pass to the component. + + Returns: + The component. + """ + return Box.create(*children, **props, display=["none", "block", "block", "none"]) + + +def desktop_only(*children, **props): + """Create a component that is only visible on desktop. + + Args: + *children: The children to pass to the component. + **props: The props to pass to the component. + + Returns: + The component. + """ + return Box.create(*children, **props, display=["none", "none", "none", "block"]) + + +def tablet_and_desktop(*children, **props): + """Create a component that is only visible on tablet and desktop. + + Args: + *children: The children to pass to the component. + **props: The props to pass to the component. + + Returns: + The component. + """ + return Box.create(*children, **props, display=["none", "block", "block", "block"]) + + +def mobile_and_tablet(*children, **props): + """Create a component that is only visible on mobile and tablet. + + Args: + *children: The children to pass to the component. + **props: The props to pass to the component. + + Returns: + The component. + """ + return Box.create(*children, **props, display=["block", "block", "block", "none"]) diff --git a/tests/components/layout/test_cond.py b/tests/components/layout/test_cond.py index fe30c372d..23a94c734 100644 --- a/tests/components/layout/test_cond.py +++ b/tests/components/layout/test_cond.py @@ -4,8 +4,7 @@ from typing import Any import pytest import pynecone as pc -from pynecone.components import cond -from pynecone.components.layout.cond import Cond +from pynecone.components.layout.cond import Cond, cond from pynecone.components.layout.fragment import Fragment from pynecone.components.typography.text import Text from pynecone.var import Var