add_style api (#3202)
This commit is contained in:
parent
d68792f7b3
commit
57476966f3
@ -833,9 +833,7 @@ class App(Base):
|
||||
|
||||
for _route, component in self.pages.items():
|
||||
# Merge the component style with the app style.
|
||||
component._add_style_recursive(self.style)
|
||||
|
||||
component.apply_theme(self.theme)
|
||||
component._add_style_recursive(self.style, self.theme)
|
||||
|
||||
# Add component._get_all_imports() to all_imports.
|
||||
all_imports.update(component._get_all_imports())
|
||||
|
@ -263,9 +263,18 @@ def _compile_stateful_components(
|
||||
# Reset this flag to render the actual component.
|
||||
component.rendered_as_shared = False
|
||||
|
||||
# Include dynamic imports in the shared component.
|
||||
if dynamic_imports := component._get_all_dynamic_imports():
|
||||
rendered_components.update(
|
||||
{dynamic_import: None for dynamic_import in dynamic_imports}
|
||||
)
|
||||
|
||||
# Include custom code in the shared component.
|
||||
rendered_components.update(
|
||||
{code: None for code in component._get_all_custom_code()},
|
||||
)
|
||||
|
||||
# Include all imports in the shared component.
|
||||
all_import_dicts.append(component._get_all_imports())
|
||||
|
||||
# Indicate that this component now imports from the shared file.
|
||||
|
@ -608,6 +608,8 @@ class Component(BaseComponent, ABC):
|
||||
def _apply_theme(self, theme: Optional[Component]):
|
||||
"""Apply the theme to this component.
|
||||
|
||||
Deprecated. Use add_style instead.
|
||||
|
||||
Args:
|
||||
theme: The theme to apply.
|
||||
"""
|
||||
@ -779,44 +781,119 @@ class Component(BaseComponent, ABC):
|
||||
|
||||
return cls(children=children, **props)
|
||||
|
||||
def _add_style(self, style: dict):
|
||||
"""Add additional style to the component.
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Downstream components can override this method to return a style dict
|
||||
that will be applied to the component.
|
||||
|
||||
Returns:
|
||||
The style to add.
|
||||
"""
|
||||
return None
|
||||
|
||||
def _add_style(self) -> Style:
|
||||
"""Call add_style for all bases in the MRO.
|
||||
|
||||
Downstream components should NOT override. Use add_style instead.
|
||||
|
||||
Returns:
|
||||
The style to add.
|
||||
"""
|
||||
styles = []
|
||||
vars = []
|
||||
|
||||
# Walk the MRO to call all `add_style` methods.
|
||||
for base in self._iter_parent_classes_with_method("add_style"):
|
||||
s = base.add_style(self) # type: ignore
|
||||
if s is not None:
|
||||
styles.append(s)
|
||||
vars.append(s._var_data)
|
||||
|
||||
_style = Style()
|
||||
for s in reversed(styles):
|
||||
_style.update(s)
|
||||
|
||||
_style._var_data = VarData.merge(*vars)
|
||||
return _style
|
||||
|
||||
def _get_component_style(self, styles: ComponentStyle) -> Style | None:
|
||||
"""Get the style to the component from `App.style`.
|
||||
|
||||
Args:
|
||||
style: A style dict to apply.
|
||||
"""
|
||||
self.style.update(style)
|
||||
styles: The style to apply.
|
||||
|
||||
def _add_style_recursive(self, style: ComponentStyle) -> Component:
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
component_style = None
|
||||
if type(self) in styles:
|
||||
component_style = Style(styles[type(self)])
|
||||
if self.create in styles:
|
||||
component_style = Style(styles[self.create])
|
||||
return component_style
|
||||
|
||||
def _add_style_recursive(
|
||||
self, style: ComponentStyle, theme: Optional[Component] = None
|
||||
) -> Component:
|
||||
"""Add additional style to the component and its children.
|
||||
|
||||
Apply order is as follows (with the latest overriding the earliest):
|
||||
1. Default style from `_add_style`/`add_style`.
|
||||
2. User-defined style from `App.style`.
|
||||
3. User-defined style from `Component.style`.
|
||||
4. style dict and css props passed to the component instance.
|
||||
|
||||
Args:
|
||||
style: A dict from component to styling.
|
||||
theme: The theme to apply. (for retro-compatibility with deprecated _apply_theme API)
|
||||
|
||||
Raises:
|
||||
UserWarning: If `_add_style` has been overridden.
|
||||
|
||||
Returns:
|
||||
The component with the additional style.
|
||||
"""
|
||||
component_style = None
|
||||
if type(self) in style:
|
||||
# Extract the style for this component.
|
||||
component_style = Style(style[type(self)])
|
||||
if self.create in style:
|
||||
component_style = Style(style[self.create])
|
||||
if component_style is not None:
|
||||
# Only add style props that are not overridden.
|
||||
component_style = {
|
||||
k: v for k, v in component_style.items() if k not in self.style
|
||||
}
|
||||
# 1. Default style from `_add_style`/`add_style`.
|
||||
if type(self)._add_style != Component._add_style:
|
||||
raise UserWarning(
|
||||
"Do not override _add_style directly. Use add_style instead."
|
||||
)
|
||||
new_style = self._add_style()
|
||||
style_vars = [new_style._var_data]
|
||||
|
||||
# Add the style to the component.
|
||||
self._add_style(component_style)
|
||||
# 2. User-defined style from `App.style`.
|
||||
component_style = self._get_component_style(style)
|
||||
if component_style:
|
||||
new_style.update(component_style)
|
||||
style_vars.append(component_style._var_data)
|
||||
|
||||
# 3. User-defined style from `Component.style`.
|
||||
# Apply theme for retro-compatibility with deprecated _apply_theme API
|
||||
if type(self)._apply_theme != Component._apply_theme:
|
||||
console.deprecate(
|
||||
f"{self.__class__.__name__}._apply_theme",
|
||||
reason="use add_style instead",
|
||||
deprecation_version="0.5.0",
|
||||
removal_version="0.6.0",
|
||||
)
|
||||
self._apply_theme(theme)
|
||||
|
||||
# 4. style dict and css props passed to the component instance.
|
||||
new_style.update(self.style)
|
||||
style_vars.append(self.style._var_data)
|
||||
|
||||
new_style._var_data = VarData.merge(*style_vars)
|
||||
|
||||
# Assign the new style
|
||||
self.style = new_style
|
||||
|
||||
# Recursively add style to the children.
|
||||
for child in self.children:
|
||||
# Skip BaseComponent and StatefulComponent children.
|
||||
if not isinstance(child, Component):
|
||||
continue
|
||||
child._add_style_recursive(style)
|
||||
child._add_style_recursive(style, theme)
|
||||
return self
|
||||
|
||||
def _get_style(self) -> dict:
|
||||
|
@ -102,15 +102,6 @@ class Cond(MemoizationLeaf):
|
||||
_IS_TRUE_IMPORT,
|
||||
)
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
"""Apply the theme to this component.
|
||||
|
||||
Args:
|
||||
theme: The theme to apply.
|
||||
"""
|
||||
self.comp1.apply_theme(theme) # type: ignore
|
||||
self.comp2.apply_theme(theme) # type: ignore
|
||||
|
||||
|
||||
@overload
|
||||
def cond(condition: Any, c1: Component, c2: Any) -> Component:
|
||||
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
from hashlib import md5
|
||||
from typing import Any, Callable, Iterable, Optional
|
||||
from typing import Any, Callable, Iterable
|
||||
|
||||
from reflex.components.base.fragment import Fragment
|
||||
from reflex.components.component import Component
|
||||
@ -23,17 +23,6 @@ class Foreach(Component):
|
||||
# A function from the render args to the component.
|
||||
render_fn: Callable = Fragment.create
|
||||
|
||||
# The theme if set.
|
||||
theme: Optional[Component] = None
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
"""Apply the theme to this component.
|
||||
|
||||
Args:
|
||||
theme: The theme to apply.
|
||||
"""
|
||||
self.theme = theme
|
||||
|
||||
@classmethod
|
||||
def create(cls, iterable: Var[Iterable], render_fn: Callable, **props) -> Foreach:
|
||||
"""Create a foreach component.
|
||||
@ -97,10 +86,6 @@ class Foreach(Component):
|
||||
tag = self._render()
|
||||
component = tag.render_component()
|
||||
|
||||
# Apply the theme to the children.
|
||||
if self.theme is not None:
|
||||
component.apply_theme(self.theme)
|
||||
|
||||
return dict(
|
||||
tag.add_props(
|
||||
**self.event_triggers,
|
||||
|
@ -273,18 +273,3 @@ class Match(MemoizationLeaf):
|
||||
super()._get_imports(),
|
||||
getattr(self.cond._var_data, "imports", {}),
|
||||
)
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
"""Apply the theme to this component.
|
||||
|
||||
Args:
|
||||
theme: The theme to apply.
|
||||
"""
|
||||
# apply theme to return components.
|
||||
for match_case in self.match_cases:
|
||||
if isinstance(match_case[-1], Component):
|
||||
match_case[-1].apply_theme(theme)
|
||||
|
||||
# apply theme to default component
|
||||
if isinstance(self.default, Component):
|
||||
self.default.apply_theme(theme)
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""A code component."""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Dict, Literal, Optional, Union
|
||||
|
||||
@ -491,8 +493,9 @@ class CodeBlock(Component):
|
||||
else:
|
||||
return code_block
|
||||
|
||||
def _add_style(self, style):
|
||||
self.custom_style.update(style) # type: ignore
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component."""
|
||||
self.custom_style.update(self.style)
|
||||
|
||||
def _render(self):
|
||||
out = super()._render()
|
||||
|
@ -1111,5 +1111,6 @@ class CodeBlock(Component):
|
||||
The text component.
|
||||
"""
|
||||
...
|
||||
def add_style(self) -> Style | None: ...
|
||||
@staticmethod
|
||||
def convert_theme_name(theme) -> str: ...
|
||||
|
@ -18,7 +18,6 @@ from reflex.components.radix.themes.typography.heading import Heading
|
||||
from reflex.components.radix.themes.typography.link import Link
|
||||
from reflex.components.radix.themes.typography.text import Text
|
||||
from reflex.components.tags.tag import Tag
|
||||
from reflex.style import Style
|
||||
from reflex.utils import console, imports, types
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var
|
||||
@ -230,7 +229,8 @@ class Markdown(Component):
|
||||
component = self.component_map[tag](*children, **props).set(
|
||||
special_props=special_props
|
||||
)
|
||||
component._add_style(Style(self.custom_styles.get(tag, {})))
|
||||
component.style.update(self.custom_styles.get(tag, {}))
|
||||
|
||||
return component
|
||||
|
||||
def format_component(self, tag: str, **props) -> str:
|
||||
|
@ -22,7 +22,6 @@ from reflex.components.radix.themes.typography.heading import Heading
|
||||
from reflex.components.radix.themes.typography.link import Link
|
||||
from reflex.components.radix.themes.typography.text import Text
|
||||
from reflex.components.tags.tag import Tag
|
||||
from reflex.style import Style
|
||||
from reflex.utils import console, imports, types
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var
|
||||
|
@ -5,303 +5,43 @@ from __future__ import annotations
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.components.core.match import Match
|
||||
from reflex.components.core.colors import color
|
||||
from reflex.components.lucide.icon import Icon
|
||||
from reflex.components.radix.primitives.base import RadixPrimitiveComponent
|
||||
from reflex.components.radix.themes.base import LiteralAccentColor
|
||||
from reflex.style import (
|
||||
Style,
|
||||
convert_dict_to_style_and_format_emotion,
|
||||
format_as_emotion,
|
||||
)
|
||||
from reflex.style import Style
|
||||
from reflex.utils import imports
|
||||
from reflex.vars import BaseVar, Var, VarData, get_uuid_string_var
|
||||
from reflex.vars import Var, get_uuid_string_var
|
||||
|
||||
LiteralAccordionType = Literal["single", "multiple"]
|
||||
LiteralAccordionDir = Literal["ltr", "rtl"]
|
||||
LiteralAccordionOrientation = Literal["vertical", "horizontal"]
|
||||
LiteralAccordionRootVariant = Literal["classic", "soft", "surface", "outline", "ghost"]
|
||||
LiteralAccordionRootColorScheme = Literal["primary", "accent"]
|
||||
LiteralAccordionVariant = Literal["classic", "soft", "surface", "outline", "ghost"]
|
||||
|
||||
DEFAULT_ANIMATION_DURATION = 250
|
||||
|
||||
|
||||
def get_theme_accordion_root(variant: Var[str], color_scheme: Var[str]) -> BaseVar:
|
||||
"""Get the theme for the accordion root component.
|
||||
|
||||
Args:
|
||||
variant: The variant of the accordion.
|
||||
color_scheme: The color of the accordion.
|
||||
|
||||
Returns:
|
||||
The theme for the accordion root component.
|
||||
"""
|
||||
return Match.create( # type: ignore
|
||||
variant,
|
||||
(
|
||||
"soft",
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"border_radius": "6px",
|
||||
"background_color": f"var(--{color_scheme}-3)",
|
||||
"box_shadow": "0 2px 10px var(--black-a1)",
|
||||
}
|
||||
),
|
||||
),
|
||||
(
|
||||
"outline",
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"border_radius": "6px",
|
||||
"border": f"1px solid var(--{color_scheme}-6)",
|
||||
"box_shadow": "0 2px 10px var(--black-a1)",
|
||||
}
|
||||
),
|
||||
),
|
||||
(
|
||||
"surface",
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"border_radius": "6px",
|
||||
"border": f"1px solid var(--{color_scheme}-6)",
|
||||
"background_color": f"var(--{color_scheme}-3)",
|
||||
"box_shadow": "0 2px 10px var(--black-a1)",
|
||||
}
|
||||
),
|
||||
),
|
||||
(
|
||||
"ghost",
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"border_radius": "6px",
|
||||
"background_color": "none",
|
||||
"box_shadow": "None",
|
||||
}
|
||||
),
|
||||
),
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"border_radius": "6px",
|
||||
"background_color": f"var(--{color_scheme}-9)",
|
||||
"box_shadow": "0 2px 10px var(--black-a4)",
|
||||
}
|
||||
),
|
||||
# defaults to classic
|
||||
)
|
||||
|
||||
|
||||
def get_theme_accordion_item():
|
||||
"""Get the theme for the accordion item component.
|
||||
|
||||
Returns:
|
||||
The theme for the accordion item component.
|
||||
"""
|
||||
return convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"overflow": "hidden",
|
||||
"width": "100%",
|
||||
"margin_top": "1px",
|
||||
"&:first-child": {
|
||||
"margin_top": 0,
|
||||
"border_top_left_radius": "4px",
|
||||
"border_top_right_radius": "4px",
|
||||
},
|
||||
"&:last-child": {
|
||||
"border_bottom_left_radius": "4px",
|
||||
"border_bottom_right_radius": "4px",
|
||||
},
|
||||
"&:focus-within": {
|
||||
"position": "relative",
|
||||
"z_index": 1,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def get_theme_accordion_header() -> dict[str, str]:
|
||||
"""Get the theme for the accordion header component.
|
||||
|
||||
Returns:
|
||||
The theme for the accordion header component.
|
||||
"""
|
||||
return {
|
||||
"display": "flex",
|
||||
}
|
||||
|
||||
|
||||
def get_theme_accordion_trigger(variant: str | Var, color_scheme: str | Var) -> BaseVar:
|
||||
"""Get the theme for the accordion trigger component.
|
||||
|
||||
Args:
|
||||
variant: The variant of the accordion.
|
||||
color_scheme: The color of the accordion.
|
||||
|
||||
Returns:
|
||||
The theme for the accordion trigger component.
|
||||
"""
|
||||
return Match.create( # type: ignore
|
||||
variant,
|
||||
(
|
||||
"soft",
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"color": f"var(--{color_scheme}-11)",
|
||||
"&:hover": {
|
||||
"background_color": f"var(--{color_scheme}-4)",
|
||||
},
|
||||
"& > .AccordionChevron": {
|
||||
"color": f"var(--{color_scheme}-11)",
|
||||
"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms cubic-bezier(0.87, 0, 0.13, 1)",
|
||||
},
|
||||
"&[data-state='open'] > .AccordionChevron": {
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
"font_family": "inherit",
|
||||
"width": "100%",
|
||||
"padding": "0 20px",
|
||||
"height": "45px",
|
||||
"flex": 1,
|
||||
"display": "flex",
|
||||
"align_items": "center",
|
||||
"justify_content": "space-between",
|
||||
"font_size": "15px",
|
||||
"line_height": 1,
|
||||
}
|
||||
),
|
||||
),
|
||||
(
|
||||
"outline",
|
||||
"surface",
|
||||
"ghost",
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"color": f"var(--{color_scheme}-11)",
|
||||
"&:hover": {
|
||||
"background_color": f"var(--{color_scheme}-4)",
|
||||
},
|
||||
"& > .AccordionChevron": {
|
||||
"color": f"var(--{color_scheme}-11)",
|
||||
"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms cubic-bezier(0.87, 0, 0.13, 1)",
|
||||
},
|
||||
"&[data-state='open'] > .AccordionChevron": {
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
"font_family": "inherit",
|
||||
"width": "100%",
|
||||
"padding": "0 20px",
|
||||
"height": "45px",
|
||||
"flex": 1,
|
||||
"display": "flex",
|
||||
"align_items": "center",
|
||||
"justify_content": "space-between",
|
||||
"font_size": "15px",
|
||||
"line_height": 1,
|
||||
}
|
||||
),
|
||||
),
|
||||
# defaults to classic
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"color": f"var(--{color_scheme}-9-contrast)",
|
||||
"box_shadow": f"var(--{color_scheme}-11)",
|
||||
"&:hover": {
|
||||
"background_color": f"var(--{color_scheme}-10)",
|
||||
},
|
||||
"& > .AccordionChevron": {
|
||||
"color": f"var(--{color_scheme}-9-contrast)",
|
||||
"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms cubic-bezier(0.87, 0, 0.13, 1)",
|
||||
},
|
||||
"&[data-state='open'] > .AccordionChevron": {
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
"font_family": "inherit",
|
||||
"width": "100%",
|
||||
"padding": "0 20px",
|
||||
"height": "45px",
|
||||
"flex": 1,
|
||||
"display": "flex",
|
||||
"align_items": "center",
|
||||
"justify_content": "space-between",
|
||||
"font_size": "15px",
|
||||
"line_height": 1,
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def get_theme_accordion_content(variant: str | Var, color_scheme: str | Var) -> BaseVar:
|
||||
"""Get the theme for the accordion content component.
|
||||
|
||||
Args:
|
||||
variant: The variant of the accordion.
|
||||
color_scheme: The color of the accordion.
|
||||
|
||||
Returns:
|
||||
The theme for the accordion content component.
|
||||
"""
|
||||
return Match.create( # type: ignore
|
||||
variant,
|
||||
(
|
||||
"outline",
|
||||
"ghost",
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"overflow": "hidden",
|
||||
"font_size": "10px",
|
||||
"color": f"var(--{color_scheme}-11)",
|
||||
"padding": "15px 20px",
|
||||
"&[data-state='open']": {
|
||||
"animation": Var.create(
|
||||
f"${{slideDown}} {DEFAULT_ANIMATION_DURATION}ms cubic-bezier(0.87, 0, 0.13, 1)",
|
||||
_var_is_string=True,
|
||||
),
|
||||
},
|
||||
"&[data-state='closed']": {
|
||||
"animation": Var.create(
|
||||
f"${{slideUp}} {DEFAULT_ANIMATION_DURATION}ms cubic-bezier(0.87, 0, 0.13, 1)",
|
||||
_var_is_string=True,
|
||||
),
|
||||
},
|
||||
}
|
||||
),
|
||||
),
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"overflow": "hidden",
|
||||
"font_size": "10px",
|
||||
"color": Match.create(
|
||||
variant,
|
||||
("classic", f"var(--{color_scheme}-9-contrast)"),
|
||||
f"var(--{color_scheme}-11)",
|
||||
),
|
||||
"background_color": Match.create(
|
||||
variant,
|
||||
("classic", f"var(--{color_scheme}-9)"),
|
||||
f"var(--{color_scheme}-3)",
|
||||
),
|
||||
"padding": "15px 20px",
|
||||
"&[data-state='open']": {
|
||||
"animation": Var.create(
|
||||
f"${{slideDown}} {DEFAULT_ANIMATION_DURATION}ms cubic-bezier(0.87, 0, 0.13, 1)",
|
||||
_var_is_string=True,
|
||||
),
|
||||
},
|
||||
"&[data-state='closed']": {
|
||||
"animation": Var.create(
|
||||
f"${{slideUp}} {DEFAULT_ANIMATION_DURATION}ms cubic-bezier(0.87, 0, 0.13, 1)",
|
||||
_var_is_string=True,
|
||||
),
|
||||
},
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class AccordionComponent(RadixPrimitiveComponent):
|
||||
"""Base class for all @radix-ui/accordion components."""
|
||||
|
||||
library = "@radix-ui/react-accordion@^1.1.2"
|
||||
|
||||
# The color scheme of the component.
|
||||
color_scheme: Var[LiteralAccentColor]
|
||||
|
||||
# The variant of the component.
|
||||
variant: Var[LiteralAccordionVariant] = Var.create_safe("classic")
|
||||
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component."""
|
||||
if self.color_scheme is not None:
|
||||
self.custom_attrs["data-accent-color"] = self.color_scheme
|
||||
|
||||
self.custom_attrs["data-variant"] = self.variant
|
||||
|
||||
def _exclude_props(self) -> list[str]:
|
||||
return ["color_scheme", "variant"]
|
||||
|
||||
|
||||
class AccordionRoot(AccordionComponent):
|
||||
"""An accordion component."""
|
||||
@ -332,16 +72,7 @@ class AccordionRoot(AccordionComponent):
|
||||
orientation: Var[LiteralAccordionOrientation]
|
||||
|
||||
# The variant of the accordion.
|
||||
variant: Var[LiteralAccordionRootVariant] = "classic" # type: ignore
|
||||
|
||||
# The color scheme of the accordion.
|
||||
color_scheme: Var[LiteralAccentColor] # type: ignore
|
||||
|
||||
# dynamic themes of the accordion generated at compile time.
|
||||
_dynamic_themes: Var[dict] = Var.create({}) # type: ignore
|
||||
|
||||
# The var_data associated with the component.
|
||||
_var_data: VarData = VarData() # type: ignore
|
||||
variant: Var[LiteralAccordionVariant] = Var.create_safe("classic")
|
||||
|
||||
_valid_children: List[str] = ["AccordionItem"]
|
||||
|
||||
@ -356,81 +87,12 @@ class AccordionRoot(AccordionComponent):
|
||||
Returns:
|
||||
The Accordion root Component.
|
||||
"""
|
||||
comp = super().create(*children, **props)
|
||||
for child in children:
|
||||
if isinstance(child, AccordionItem):
|
||||
child.color_scheme = props.get("color_scheme") # type: ignore
|
||||
child.variant = props.get("variant") # type: ignore
|
||||
|
||||
if comp.color_scheme is not None and not comp.color_scheme._var_state: # type: ignore
|
||||
# mark the vars of color string literals as strings so they can be formatted properly when performing a var operation.
|
||||
comp.color_scheme._var_is_string = True # type: ignore
|
||||
|
||||
if comp.variant is not None and not comp.variant._var_state: # type: ignore
|
||||
# mark the vars of variant string literals as strings so they are formatted properly in the match condition.
|
||||
comp.variant._var_is_string = True # type: ignore
|
||||
|
||||
return comp
|
||||
|
||||
def _get_style(self) -> dict:
|
||||
"""Get the style for the component.
|
||||
|
||||
Returns:
|
||||
The dictionary of the component style as value and the style notation as key.
|
||||
"""
|
||||
return {"css": self._dynamic_themes._merge(format_as_emotion(self.style))} # type: ignore
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
global_color_scheme = getattr(theme, "accent_color", None)
|
||||
|
||||
if global_color_scheme is None and self.color_scheme is None:
|
||||
raise ValueError(
|
||||
"`color_scheme` cannot be None. Either set the `color_scheme` prop on the accordion "
|
||||
"component or set the `accent_color` prop in your global theme."
|
||||
)
|
||||
|
||||
# prepare the color_scheme var to be used in an f-string(strip off the wrapping curly brace)
|
||||
color_scheme = Var.create(
|
||||
self.color_scheme if self.color_scheme is not None else global_color_scheme
|
||||
)._replace( # type: ignore
|
||||
_var_is_string=False
|
||||
)
|
||||
|
||||
accordion_theme_root = get_theme_accordion_root(
|
||||
variant=self.variant, color_scheme=color_scheme
|
||||
)
|
||||
accordion_theme_content = get_theme_accordion_content(
|
||||
variant=self.variant, color_scheme=color_scheme
|
||||
)
|
||||
accordion_theme_trigger = get_theme_accordion_trigger(
|
||||
variant=self.variant, color_scheme=color_scheme
|
||||
)
|
||||
|
||||
# extract var_data from dynamic themes.
|
||||
self._var_data = (
|
||||
self._var_data.merge( # type: ignore
|
||||
accordion_theme_trigger._var_data,
|
||||
accordion_theme_content._var_data,
|
||||
accordion_theme_root._var_data,
|
||||
)
|
||||
or self._var_data
|
||||
)
|
||||
|
||||
self._dynamic_themes = Var.create( # type: ignore
|
||||
convert_dict_to_style_and_format_emotion(
|
||||
{
|
||||
"& .AccordionItem": get_theme_accordion_item(),
|
||||
"& .AccordionHeader": get_theme_accordion_header(),
|
||||
"& .AccordionTrigger": accordion_theme_trigger,
|
||||
"& .AccordionContent": accordion_theme_content,
|
||||
}
|
||||
)
|
||||
)._merge( # type: ignore
|
||||
accordion_theme_root
|
||||
)
|
||||
|
||||
def _get_imports(self):
|
||||
return imports.merge_imports(
|
||||
super()._get_imports(),
|
||||
self._var_data.imports if self._var_data else {},
|
||||
{"@emotion/react": [imports.ImportVar(tag="keyframes")]},
|
||||
)
|
||||
return super().create(*children, **props)
|
||||
|
||||
def get_event_triggers(self) -> Dict[str, Any]:
|
||||
"""Get the events triggers signatures for the component.
|
||||
@ -443,28 +105,36 @@ class AccordionRoot(AccordionComponent):
|
||||
"on_value_change": lambda e0: [e0],
|
||||
}
|
||||
|
||||
def _get_custom_code(self) -> str:
|
||||
return """
|
||||
const slideDown = keyframes`
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
to {
|
||||
height: var(--radix-accordion-content-height);
|
||||
}
|
||||
`
|
||||
const slideUp = keyframes`
|
||||
from {
|
||||
height: var(--radix-accordion-content-height);
|
||||
}
|
||||
to {
|
||||
height: 0;
|
||||
}
|
||||
`
|
||||
"""
|
||||
def add_style(self):
|
||||
"""Add style to the component.
|
||||
|
||||
def _exclude_props(self) -> list[str]:
|
||||
return ["color_scheme", "variant"]
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style(
|
||||
{
|
||||
"border_radius": "6px",
|
||||
"box_shadow": f"0 2px 10px {color('black', 1, alpha=True)}",
|
||||
"&[data-variant='classic']": {
|
||||
"background_color": color("accent", 9),
|
||||
"box_shadow": f"0 2px 10px {color('black', 4, alpha=True)}",
|
||||
},
|
||||
"&[data-variant='soft']": {
|
||||
"background_color": color("accent", 3),
|
||||
},
|
||||
"&[data-variant='outline']": {
|
||||
"border": f"1px solid {color('accent', 6)}",
|
||||
},
|
||||
"&[data-variant='surface']": {
|
||||
"border": f"1px solid {color('accent', 6)}",
|
||||
"background_color": color("accent", 3),
|
||||
},
|
||||
"&[data-variant='ghost']": {
|
||||
"background_color": "none",
|
||||
"box_shadow": "None",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class AccordionItem(AccordionComponent):
|
||||
@ -488,13 +158,6 @@ class AccordionItem(AccordionComponent):
|
||||
|
||||
_valid_parents: List[str] = ["AccordionRoot"]
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style = Style(
|
||||
{
|
||||
**self.style,
|
||||
}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
@ -506,9 +169,9 @@ class AccordionItem(AccordionComponent):
|
||||
"""Create an accordion item.
|
||||
|
||||
Args:
|
||||
*children: The list of children to use if header and content are not provided.
|
||||
header: The header of the accordion item.
|
||||
content: The content of the accordion item.
|
||||
*children: The list of children to use if header and content are not provided.
|
||||
**props: Additional properties to apply to the accordion item.
|
||||
|
||||
Returns:
|
||||
@ -527,14 +190,55 @@ class AccordionItem(AccordionComponent):
|
||||
AccordionHeader.create(
|
||||
AccordionTrigger.create(
|
||||
header,
|
||||
AccordionIcon.create(),
|
||||
AccordionIcon.create(
|
||||
color_scheme=props.get("color_scheme"),
|
||||
variant=props.get("variant"),
|
||||
),
|
||||
color_scheme=props.get("color_scheme"),
|
||||
variant=props.get("variant"),
|
||||
),
|
||||
color_scheme=props.get("color_scheme"),
|
||||
variant=props.get("variant"),
|
||||
),
|
||||
AccordionContent.create(
|
||||
content, color_scheme=props.get("color_scheme")
|
||||
),
|
||||
AccordionContent.create(content),
|
||||
]
|
||||
|
||||
return super().create(*children, value=value, **props, class_name=cls_name)
|
||||
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
for child in self.children:
|
||||
if isinstance(child, (AccordionHeader, AccordionContent)):
|
||||
child.color_scheme = self.color_scheme
|
||||
child.variant = self.variant
|
||||
|
||||
return Style(
|
||||
{
|
||||
"overflow": "hidden",
|
||||
"width": "100%",
|
||||
"margin_top": "1px",
|
||||
"&:first-child": {
|
||||
"margin_top": 0,
|
||||
"border_top_left_radius": "4px",
|
||||
"border_top_right_radius": "4px",
|
||||
},
|
||||
"&:last-child": {
|
||||
"border_bottom_left_radius": "4px",
|
||||
"border_bottom_right_radius": "4px",
|
||||
},
|
||||
"&:focus-within": {
|
||||
"position": "relative",
|
||||
"z_index": 1,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class AccordionHeader(AccordionComponent):
|
||||
"""An accordion component."""
|
||||
@ -561,8 +265,21 @@ class AccordionHeader(AccordionComponent):
|
||||
|
||||
return super().create(*children, class_name=cls_name, **props)
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style = Style({**self.style})
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
for child in self.children:
|
||||
if isinstance(child, AccordionTrigger):
|
||||
child.color_scheme = self.color_scheme
|
||||
child.variant = self.variant
|
||||
|
||||
return Style({"display": "flex"})
|
||||
|
||||
|
||||
cubic_bezier = "cubic-bezier(0.87, 0, 0.13, 1)"
|
||||
|
||||
|
||||
class AccordionTrigger(AccordionComponent):
|
||||
@ -590,8 +307,52 @@ class AccordionTrigger(AccordionComponent):
|
||||
|
||||
return super().create(*children, class_name=cls_name, **props)
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style = Style({**self.style})
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
for child in self.children:
|
||||
if isinstance(child, AccordionIcon):
|
||||
child.color_scheme = self.color_scheme
|
||||
child.variant = self.variant
|
||||
|
||||
return Style(
|
||||
{
|
||||
"color": color("accent", 11),
|
||||
"line_height": 1,
|
||||
"font_size": "15px",
|
||||
"justify_content": "space-between",
|
||||
"align_items": "center",
|
||||
"flex": 1,
|
||||
"display": "flex",
|
||||
"padding": "0 20px",
|
||||
"height": "45px",
|
||||
"font_family": "inherit",
|
||||
"width": "100%",
|
||||
"&[data-state='open'] > .AccordionChevron": {
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
"&:hover": {
|
||||
"background_color": color("accent", 4),
|
||||
},
|
||||
"& > .AccordionChevron": {
|
||||
"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms {cubic_bezier}",
|
||||
},
|
||||
"&[data-variant='classic']": {
|
||||
"color": color("accent", 12),
|
||||
"box_shadow": color("accent", 11),
|
||||
"&:hover": {
|
||||
"background_color": color("accent", 10),
|
||||
},
|
||||
"& > .AccordionChevron": {
|
||||
"color": color("accent", 12),
|
||||
"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms {cubic_bezier}",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class AccordionIcon(Icon):
|
||||
@ -623,6 +384,14 @@ class AccordionContent(AccordionComponent):
|
||||
|
||||
alias = "RadixAccordionContent"
|
||||
|
||||
def add_imports(self) -> imports.ImportDict:
|
||||
"""Add imports to the component.
|
||||
|
||||
Returns:
|
||||
The imports of the component.
|
||||
"""
|
||||
return {"@emotion/react": [imports.ImportVar(tag="keyframes")]}
|
||||
|
||||
@classmethod
|
||||
def create(cls, *children, **props) -> Component:
|
||||
"""Create the Accordion content component.
|
||||
@ -641,14 +410,66 @@ class AccordionContent(AccordionComponent):
|
||||
|
||||
return super().create(*children, class_name=cls_name, **props)
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style = Style({**self.style})
|
||||
def add_custom_code(self) -> list[str]:
|
||||
"""Add custom code to the component.
|
||||
|
||||
# def _get_imports(self):
|
||||
# return {
|
||||
# **super()._get_imports(),
|
||||
# "@emotion/react": [imports.ImportVar(tag="keyframes")],
|
||||
# }
|
||||
Returns:
|
||||
The custom code of the component.
|
||||
"""
|
||||
return [
|
||||
"""
|
||||
const slideDown = keyframes`
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
to {
|
||||
height: var(--radix-accordion-content-height);
|
||||
}
|
||||
`
|
||||
const slideUp = keyframes`
|
||||
from {
|
||||
height: var(--radix-accordion-content-height);
|
||||
}
|
||||
to {
|
||||
height: 0;
|
||||
}
|
||||
`
|
||||
"""
|
||||
]
|
||||
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
slideDown = Var.create(
|
||||
f"${{slideDown}} {DEFAULT_ANIMATION_DURATION}ms {cubic_bezier}",
|
||||
_var_is_string=True,
|
||||
)
|
||||
|
||||
slideUp = Var.create(
|
||||
f"${{slideUp}} {DEFAULT_ANIMATION_DURATION}ms {cubic_bezier}",
|
||||
_var_is_string=True,
|
||||
)
|
||||
|
||||
return Style(
|
||||
{
|
||||
"overflow": "hidden",
|
||||
"font_size": "10px",
|
||||
"color": color("accent", 11),
|
||||
"background_color": color("accent", 3),
|
||||
"padding": "0 15px",
|
||||
"&[data-state='open']": {"animation": slideDown},
|
||||
"&[data-state='closed']": {"animation": slideUp},
|
||||
"&[data-variant='classic']": {
|
||||
"color": color("accent", 12),
|
||||
"background_color": color("accent", 9),
|
||||
},
|
||||
"&[data-variant='outline']": {"background_color": "transparent"},
|
||||
"&[data-variant='ghost']": {"background_color": "transparent"},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class Accordion(ComponentNamespace):
|
||||
|
@ -9,41 +9,95 @@ from reflex.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.components.core.match import Match
|
||||
from reflex.components.core.colors import color
|
||||
from reflex.components.lucide.icon import Icon
|
||||
from reflex.components.radix.primitives.base import RadixPrimitiveComponent
|
||||
from reflex.components.radix.themes.base import LiteralAccentColor
|
||||
from reflex.style import (
|
||||
Style,
|
||||
convert_dict_to_style_and_format_emotion,
|
||||
format_as_emotion,
|
||||
)
|
||||
from reflex.style import Style
|
||||
from reflex.utils import imports
|
||||
from reflex.vars import BaseVar, Var, VarData, get_uuid_string_var
|
||||
from reflex.vars import Var, get_uuid_string_var
|
||||
|
||||
LiteralAccordionType = Literal["single", "multiple"]
|
||||
LiteralAccordionDir = Literal["ltr", "rtl"]
|
||||
LiteralAccordionOrientation = Literal["vertical", "horizontal"]
|
||||
LiteralAccordionRootVariant = Literal["classic", "soft", "surface", "outline", "ghost"]
|
||||
LiteralAccordionRootColorScheme = Literal["primary", "accent"]
|
||||
LiteralAccordionVariant = Literal["classic", "soft", "surface", "outline", "ghost"]
|
||||
DEFAULT_ANIMATION_DURATION = 250
|
||||
|
||||
def get_theme_accordion_root(variant: Var[str], color_scheme: Var[str]) -> BaseVar: ...
|
||||
def get_theme_accordion_item(): ...
|
||||
def get_theme_accordion_header() -> dict[str, str]: ...
|
||||
def get_theme_accordion_trigger(
|
||||
variant: str | Var, color_scheme: str | Var
|
||||
) -> BaseVar: ...
|
||||
def get_theme_accordion_content(
|
||||
variant: str | Var, color_scheme: str | Var
|
||||
) -> BaseVar: ...
|
||||
|
||||
class AccordionComponent(RadixPrimitiveComponent):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
color_scheme: Optional[
|
||||
Union[
|
||||
Var[
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
]
|
||||
],
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
variant: Optional[
|
||||
Union[
|
||||
Var[Literal["classic", "soft", "surface", "outline", "ghost"]],
|
||||
Literal["classic", "soft", "surface", "outline", "ghost"],
|
||||
]
|
||||
] = None,
|
||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
@ -102,6 +156,8 @@ class AccordionComponent(RadixPrimitiveComponent):
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
color_scheme: The color scheme of the component.
|
||||
variant: The variant of the component.
|
||||
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.
|
||||
@ -208,8 +264,6 @@ class AccordionRoot(AccordionComponent):
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
_dynamic_themes: Optional[Union[Var[dict], dict]] = None,
|
||||
_var_data: Optional[VarData] = None,
|
||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
@ -278,10 +332,8 @@ class AccordionRoot(AccordionComponent):
|
||||
disabled: Whether or not the accordion is disabled.
|
||||
dir: The reading direction of the accordion when applicable.
|
||||
orientation: The orientation of the accordion.
|
||||
variant: The variant of the accordion.
|
||||
color_scheme: The color scheme of the accordion.
|
||||
_dynamic_themes: dynamic themes of the accordion generated at compile time.
|
||||
_var_data: The var_data associated with the component.
|
||||
variant: The variant of the component.
|
||||
color_scheme: The color scheme of the component.
|
||||
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.
|
||||
@ -296,6 +348,7 @@ class AccordionRoot(AccordionComponent):
|
||||
"""
|
||||
...
|
||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||
def add_style(self): ...
|
||||
|
||||
class AccordionItem(AccordionComponent):
|
||||
@overload
|
||||
@ -307,6 +360,74 @@ class AccordionItem(AccordionComponent):
|
||||
content: Optional[Union[Component, Var]] = None,
|
||||
value: Optional[Union[Var[str], str]] = None,
|
||||
disabled: Optional[Union[Var[bool], bool]] = None,
|
||||
color_scheme: Optional[
|
||||
Union[
|
||||
Var[
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
]
|
||||
],
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
variant: Optional[
|
||||
Union[
|
||||
Var[Literal["classic", "soft", "surface", "outline", "ghost"]],
|
||||
Literal["classic", "soft", "surface", "outline", "ghost"],
|
||||
]
|
||||
] = None,
|
||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
@ -364,11 +485,13 @@ class AccordionItem(AccordionComponent):
|
||||
"""Create an accordion item.
|
||||
|
||||
Args:
|
||||
*children: The list of children to use if header and content are not provided.
|
||||
header: The header of the accordion item.
|
||||
content: The content of the accordion item.
|
||||
*children: The list of children to use if header and content are not provided.
|
||||
value: A unique identifier for the item.
|
||||
disabled: When true, prevents the user from interacting with the item.
|
||||
color_scheme: The color scheme of the component.
|
||||
variant: The variant of the component.
|
||||
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.
|
||||
@ -382,6 +505,7 @@ class AccordionItem(AccordionComponent):
|
||||
The accordion item.
|
||||
"""
|
||||
...
|
||||
def add_style(self) -> Style | None: ...
|
||||
|
||||
class AccordionHeader(AccordionComponent):
|
||||
@overload
|
||||
@ -389,6 +513,74 @@ class AccordionHeader(AccordionComponent):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
color_scheme: Optional[
|
||||
Union[
|
||||
Var[
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
]
|
||||
],
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
variant: Optional[
|
||||
Union[
|
||||
Var[Literal["classic", "soft", "surface", "outline", "ghost"]],
|
||||
Literal["classic", "soft", "surface", "outline", "ghost"],
|
||||
]
|
||||
] = None,
|
||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
@ -447,6 +639,8 @@ class AccordionHeader(AccordionComponent):
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
color_scheme: The color scheme of the component.
|
||||
variant: The variant of the component.
|
||||
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.
|
||||
@ -460,6 +654,9 @@ class AccordionHeader(AccordionComponent):
|
||||
The Accordion header Component.
|
||||
"""
|
||||
...
|
||||
def add_style(self) -> Style | None: ...
|
||||
|
||||
cubic_bezier = "cubic-bezier(0.87, 0, 0.13, 1)"
|
||||
|
||||
class AccordionTrigger(AccordionComponent):
|
||||
@overload
|
||||
@ -467,6 +664,74 @@ class AccordionTrigger(AccordionComponent):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
color_scheme: Optional[
|
||||
Union[
|
||||
Var[
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
]
|
||||
],
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
variant: Optional[
|
||||
Union[
|
||||
Var[Literal["classic", "soft", "surface", "outline", "ghost"]],
|
||||
Literal["classic", "soft", "surface", "outline", "ghost"],
|
||||
]
|
||||
] = None,
|
||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
@ -525,6 +790,8 @@ class AccordionTrigger(AccordionComponent):
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
color_scheme: The color scheme of the component.
|
||||
variant: The variant of the component.
|
||||
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.
|
||||
@ -538,6 +805,7 @@ class AccordionTrigger(AccordionComponent):
|
||||
The Accordion trigger Component.
|
||||
"""
|
||||
...
|
||||
def add_style(self) -> Style | None: ...
|
||||
|
||||
class AccordionIcon(Icon):
|
||||
@overload
|
||||
@ -618,11 +886,80 @@ class AccordionIcon(Icon):
|
||||
...
|
||||
|
||||
class AccordionContent(AccordionComponent):
|
||||
def add_imports(self) -> imports.ImportDict: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
color_scheme: Optional[
|
||||
Union[
|
||||
Var[
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
]
|
||||
],
|
||||
Literal[
|
||||
"tomato",
|
||||
"red",
|
||||
"ruby",
|
||||
"crimson",
|
||||
"pink",
|
||||
"plum",
|
||||
"purple",
|
||||
"violet",
|
||||
"iris",
|
||||
"indigo",
|
||||
"blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"jade",
|
||||
"green",
|
||||
"grass",
|
||||
"brown",
|
||||
"orange",
|
||||
"sky",
|
||||
"mint",
|
||||
"lime",
|
||||
"yellow",
|
||||
"amber",
|
||||
"gold",
|
||||
"bronze",
|
||||
"gray",
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
variant: Optional[
|
||||
Union[
|
||||
Var[Literal["classic", "soft", "surface", "outline", "ghost"]],
|
||||
Literal["classic", "soft", "surface", "outline", "ghost"],
|
||||
]
|
||||
] = None,
|
||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
@ -681,6 +1018,8 @@ class AccordionContent(AccordionComponent):
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
color_scheme: The color scheme of the component.
|
||||
variant: The variant of the component.
|
||||
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.
|
||||
@ -694,6 +1033,8 @@ class AccordionContent(AccordionComponent):
|
||||
The Accordion content Component.
|
||||
"""
|
||||
...
|
||||
def add_custom_code(self) -> list[str]: ...
|
||||
def add_style(self) -> Style | None: ...
|
||||
|
||||
class Accordion(ComponentNamespace):
|
||||
content = staticmethod(AccordionContent.create)
|
||||
|
@ -4,10 +4,11 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, Literal
|
||||
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.components.component import ComponentNamespace
|
||||
from reflex.components.el.elements.forms import Form as HTMLForm
|
||||
from reflex.components.radix.themes.components.text_field import TextFieldRoot
|
||||
from reflex.constants.event import EventTriggers
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
|
||||
from .base import RadixPrimitiveComponentWithClassName
|
||||
@ -37,11 +38,13 @@ class FormRoot(FormComponent, HTMLForm):
|
||||
EventTriggers.ON_CLEAR_SERVER_ERRORS: lambda: [],
|
||||
}
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
return {
|
||||
"width": "260px",
|
||||
**self.style,
|
||||
}
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style({"width": "260px"})
|
||||
|
||||
|
||||
class FormField(FormComponent):
|
||||
@ -57,12 +60,13 @@ class FormField(FormComponent):
|
||||
# Flag to mark the form field as invalid, for server side validation.
|
||||
server_invalid: Var[bool]
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
return {
|
||||
"display": "grid",
|
||||
"margin_bottom": "10px",
|
||||
**self.style,
|
||||
}
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style({"display": "grid", "margin_bottom": "10px"})
|
||||
|
||||
|
||||
class FormLabel(FormComponent):
|
||||
@ -72,13 +76,13 @@ class FormLabel(FormComponent):
|
||||
|
||||
alias = "RadixFormLabel"
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
return {
|
||||
"font_size": "15px",
|
||||
"font_weight": "500",
|
||||
"line_height": "35px",
|
||||
**self.style,
|
||||
}
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style({"font_size": "15px", "font_weight": "500", "line_height": "35px"})
|
||||
|
||||
|
||||
class FormControl(FormComponent):
|
||||
@ -145,13 +149,13 @@ class FormMessage(FormComponent):
|
||||
# Forces the message to be shown. This is useful when using server-side validation.
|
||||
force_match: Var[bool]
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
return {
|
||||
"font_size": "13px",
|
||||
"opacity": "0.8",
|
||||
"color": "white",
|
||||
**self.style,
|
||||
}
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style({"font_size": "13px", "opacity": "0.8", "color": "white"})
|
||||
|
||||
|
||||
class FormValidityState(FormComponent):
|
||||
|
@ -8,10 +8,11 @@ from reflex.vars import Var, BaseVar, ComputedVar
|
||||
from reflex.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
from typing import Any, Dict, Literal
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.components.component import ComponentNamespace
|
||||
from reflex.components.el.elements.forms import Form as HTMLForm
|
||||
from reflex.components.radix.themes.components.text_field import TextFieldRoot
|
||||
from reflex.constants.event import EventTriggers
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
from .base import RadixPrimitiveComponentWithClassName
|
||||
|
||||
@ -95,6 +96,7 @@ class FormComponent(RadixPrimitiveComponentWithClassName):
|
||||
|
||||
class FormRoot(FormComponent, HTMLForm):
|
||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
@ -273,6 +275,7 @@ class FormRoot(FormComponent, HTMLForm):
|
||||
...
|
||||
|
||||
class FormField(FormComponent):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
@ -355,6 +358,7 @@ class FormField(FormComponent):
|
||||
...
|
||||
|
||||
class FormLabel(FormComponent):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
@ -528,6 +532,7 @@ LiteralMatcher = Literal[
|
||||
]
|
||||
|
||||
class FormMessage(FormComponent):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
|
@ -28,20 +28,24 @@ class ProgressRoot(ProgressComponent):
|
||||
# Override theme radius for progress bar: "none" | "small" | "medium" | "large" | "full"
|
||||
radius: Var[LiteralRadius]
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
if self.radius is not None:
|
||||
self.custom_attrs["data-radius"] = self.radius
|
||||
|
||||
self.style = Style(
|
||||
return Style(
|
||||
{
|
||||
"position": "relative",
|
||||
"overflow": "hidden",
|
||||
"background": "var(--gray-a3)",
|
||||
"background": color("gray", 3, alpha=True),
|
||||
"border_radius": "max(var(--radius-2), var(--radius-full))",
|
||||
"width": "100%",
|
||||
"height": "20px",
|
||||
"boxShadow": "inset 0 0 0 1px var(--gray-a5)",
|
||||
**self.style,
|
||||
"boxShadow": f"inset 0 0 0 1px {color('gray', 5, alpha=True)}",
|
||||
}
|
||||
)
|
||||
|
||||
@ -65,22 +69,26 @@ class ProgressIndicator(ProgressComponent):
|
||||
# The color scheme of the progress indicator.
|
||||
color_scheme: Var[LiteralAccentColor]
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
if self.color_scheme is not None:
|
||||
self.custom_attrs["data-accent-color"] = self.color_scheme
|
||||
|
||||
self.style = Style(
|
||||
return Style(
|
||||
{
|
||||
"background_color": color("accent", 9),
|
||||
"width": "100%",
|
||||
"height": "100%",
|
||||
f"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms linear",
|
||||
"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms linear",
|
||||
"&[data_state='loading']": {
|
||||
"transition": f"transform {DEFAULT_ANIMATION_DURATION}ms linear",
|
||||
},
|
||||
"transform": f"translateX(calc(-100% + ({self.value} / {self.max} * 100%)))", # type: ignore
|
||||
"boxShadow": "inset 0 0 0 1px var(--gray-a5)",
|
||||
**self.style,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -95,6 +95,7 @@ class ProgressComponent(RadixPrimitiveComponentWithClassName):
|
||||
...
|
||||
|
||||
class ProgressRoot(ProgressComponent):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
@ -180,6 +181,7 @@ class ProgressRoot(ProgressComponent):
|
||||
...
|
||||
|
||||
class ProgressIndicator(ProgressComponent):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
|
@ -59,8 +59,13 @@ class SliderRoot(SliderComponent):
|
||||
"on_value_commit": lambda e0: [e0], # trigger when thumb is released
|
||||
}
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style = Style(
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style(
|
||||
{
|
||||
"position": "relative",
|
||||
"display": "flex",
|
||||
@ -74,7 +79,6 @@ class SliderRoot(SliderComponent):
|
||||
"width": "20px",
|
||||
"height": "100px",
|
||||
},
|
||||
**self.style,
|
||||
}
|
||||
)
|
||||
|
||||
@ -85,18 +89,20 @@ class SliderTrack(SliderComponent):
|
||||
tag = "Track"
|
||||
alias = "RadixSliderTrack"
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style = Style(
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style(
|
||||
{
|
||||
"position": "relative",
|
||||
"flex_grow": "1",
|
||||
"background_color": "black",
|
||||
"border_radius": "9999px",
|
||||
"height": "3px",
|
||||
"&[data-orientation='vertical']": {
|
||||
"width": "3px",
|
||||
},
|
||||
**self.style,
|
||||
"&[data-orientation='vertical']": {"width": "3px"},
|
||||
}
|
||||
)
|
||||
|
||||
@ -107,16 +113,18 @@ class SliderRange(SliderComponent):
|
||||
tag = "Range"
|
||||
alias = "RadixSliderRange"
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style = Style(
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style(
|
||||
{
|
||||
"position": "absolute",
|
||||
"background_color": "white",
|
||||
"height": "100%",
|
||||
"&[data-orientation='vertical']": {
|
||||
"width": "100%",
|
||||
},
|
||||
**self.style,
|
||||
"&[data-orientation='vertical']": {"width": "100%"},
|
||||
}
|
||||
)
|
||||
|
||||
@ -127,8 +135,13 @@ class SliderThumb(SliderComponent):
|
||||
tag = "Thumb"
|
||||
alias = "RadixSliderThumb"
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style = Style(
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style(
|
||||
{
|
||||
"display": "block",
|
||||
"width": "20px",
|
||||
@ -143,7 +156,6 @@ class SliderThumb(SliderComponent):
|
||||
"outline": "none",
|
||||
"box_shadow": "0 0 0 4px gray",
|
||||
},
|
||||
**self.style,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -96,6 +96,7 @@ class SliderComponent(RadixPrimitiveComponentWithClassName):
|
||||
|
||||
class SliderRoot(SliderComponent):
|
||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
@ -196,6 +197,7 @@ class SliderRoot(SliderComponent):
|
||||
...
|
||||
|
||||
class SliderTrack(SliderComponent):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
@ -274,6 +276,7 @@ class SliderTrack(SliderComponent):
|
||||
...
|
||||
|
||||
class SliderRange(SliderComponent):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
@ -352,6 +355,7 @@ class SliderRange(SliderComponent):
|
||||
...
|
||||
|
||||
class SliderThumb(SliderComponent):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""Interactive components provided by @radix-ui/themes."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal
|
||||
|
||||
@ -6,6 +7,7 @@ from reflex import el
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.core.match import Match
|
||||
from reflex.components.lucide import Icon
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
|
||||
from ..base import (
|
||||
@ -68,25 +70,25 @@ class IconButton(el.Button, RadixLoadingProp, RadixThemesComponent):
|
||||
"IconButton requires a child icon. Pass a string as the first child or a rx.icon."
|
||||
)
|
||||
if "size" in props:
|
||||
RADIX_TO_LUCIDE_SIZE = {"1": "12px", "2": "24px", "3": "36px", "4": "48px"}
|
||||
|
||||
if isinstance(props["size"], str):
|
||||
RADIX_TO_LUCIDE_SIZE = {
|
||||
"1": "12px",
|
||||
"2": "24px",
|
||||
"3": "36px",
|
||||
"4": "48px",
|
||||
}
|
||||
children[0].size = RADIX_TO_LUCIDE_SIZE[props["size"]]
|
||||
else:
|
||||
children[0].size = Match.create(
|
||||
props["size"],
|
||||
("1", "12px"),
|
||||
("2", "24px"),
|
||||
("3", "36px"),
|
||||
("4", "48px"),
|
||||
*[(size, px) for size, px in RADIX_TO_LUCIDE_SIZE.items()],
|
||||
"12px",
|
||||
)
|
||||
props.setdefault("padding", "6px")
|
||||
return super().create(*children, **props)
|
||||
|
||||
def add_style(self):
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style({"padding": "6px"})
|
||||
|
||||
|
||||
icon_button = IconButton.create
|
||||
|
@ -12,6 +12,7 @@ from reflex import el
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.core.match import Match
|
||||
from reflex.components.lucide import Icon
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
from ..base import (
|
||||
LiteralAccentColor,
|
||||
@ -280,5 +281,6 @@ class IconButton(el.Button, RadixLoadingProp, RadixThemesComponent):
|
||||
The IconButton component.
|
||||
"""
|
||||
...
|
||||
def add_style(self): ...
|
||||
|
||||
icon_button = IconButton.create
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.style import Style
|
||||
|
||||
from .flex import Flex
|
||||
|
||||
@ -10,8 +10,13 @@ from .flex import Flex
|
||||
class Center(Flex):
|
||||
"""A center component."""
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style.update(
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style that center the content.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style(
|
||||
{
|
||||
"display": "flex",
|
||||
"align_items": "center",
|
||||
|
@ -7,10 +7,11 @@ from typing import Any, Dict, Literal, Optional, Union, overload
|
||||
from reflex.vars import Var, BaseVar, ComputedVar
|
||||
from reflex.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
from reflex.components.component import Component
|
||||
from reflex.style import Style
|
||||
from .flex import Flex
|
||||
|
||||
class Center(Flex):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""List components."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable, Literal, Optional, Union
|
||||
|
||||
@ -77,12 +78,16 @@ class BaseList(Component):
|
||||
style["gap"] = props["gap"]
|
||||
return super().create(*children, **props)
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style = Style(
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style(
|
||||
{
|
||||
"direction": "column",
|
||||
"list_style_position": "inside",
|
||||
**self.style,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -157,6 +157,7 @@ class BaseList(Component):
|
||||
|
||||
"""
|
||||
...
|
||||
def add_style(self) -> Style | None: ...
|
||||
|
||||
class UnorderedList(BaseList, Ul):
|
||||
@overload
|
||||
@ -165,7 +166,7 @@ class UnorderedList(BaseList, Ul):
|
||||
cls,
|
||||
*children,
|
||||
items: Optional[Union[Var[Iterable], Iterable]] = None,
|
||||
list_style_type: Optional[Literal["none", "disc", "circle", "square"]] = "disc",
|
||||
list_style_type: Optional[LiteralListStyleTypeUnordered] = "disc",
|
||||
access_key: Optional[
|
||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||
] = None,
|
||||
@ -302,24 +303,7 @@ class OrderedList(BaseList, Ol):
|
||||
cls,
|
||||
*children,
|
||||
items: Optional[Union[Var[Iterable], Iterable]] = None,
|
||||
list_style_type: Optional[
|
||||
Literal[
|
||||
"none",
|
||||
"decimal",
|
||||
"decimal-leading-zero",
|
||||
"lower-roman",
|
||||
"upper-roman",
|
||||
"lower-greek",
|
||||
"lower-latin",
|
||||
"upper-latin",
|
||||
"armenian",
|
||||
"georgian",
|
||||
"lower-alpha",
|
||||
"upper-alpha",
|
||||
"hiragana",
|
||||
"katakana",
|
||||
]
|
||||
] = "decimal",
|
||||
list_style_type: Optional[LiteralListStyleTypeOrdered] = "decimal",
|
||||
reversed: Optional[
|
||||
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
|
||||
] = None,
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.style import Style
|
||||
|
||||
from .flex import Flex
|
||||
|
||||
@ -10,8 +10,13 @@ from .flex import Flex
|
||||
class Spacer(Flex):
|
||||
"""A spacer component."""
|
||||
|
||||
def _apply_theme(self, theme: Component):
|
||||
self.style.update(
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
return Style(
|
||||
{
|
||||
"flex": 1,
|
||||
"justify_self": "stretch",
|
||||
|
@ -7,10 +7,11 @@ from typing import Any, Dict, Literal, Optional, Union, overload
|
||||
from reflex.vars import Var, BaseVar, ComputedVar
|
||||
from reflex.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
from reflex.components.component import Component
|
||||
from reflex.style import Style
|
||||
from .flex import Flex
|
||||
|
||||
class Spacer(Flex):
|
||||
def add_style(self) -> Style | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
|
@ -37,6 +37,8 @@ ColorType = Literal[
|
||||
"bronze",
|
||||
"gray",
|
||||
"accent",
|
||||
"black",
|
||||
"white",
|
||||
]
|
||||
|
||||
ShadeType = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
|
||||
|
@ -1,5 +1,7 @@
|
||||
"""To experiment with layout component, move them to reflex/components later."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from reflex import color, cond
|
||||
from reflex.components.base.fragment import Fragment
|
||||
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf
|
||||
@ -9,6 +11,7 @@ from reflex.components.radix.themes.layout import Box, Container, HStack
|
||||
from reflex.event import call_script
|
||||
from reflex.experimental import hooks
|
||||
from reflex.state import ComponentState
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
|
||||
|
||||
@ -26,23 +29,38 @@ class Sidebar(Box, MemoizationLeaf):
|
||||
Returns:
|
||||
The sidebar component.
|
||||
"""
|
||||
props.setdefault("border_right", f"1px solid {color('accent', 12)}")
|
||||
props.setdefault("background_color", color("accent", 1))
|
||||
props.setdefault("width", "20vw")
|
||||
props.setdefault("height", "100vh")
|
||||
props.setdefault("position", "fixed")
|
||||
# props.setdefault("border_right", f"1px solid {color('accent', 12)}")
|
||||
# props.setdefault("background_color", color("accent", 1))
|
||||
# props.setdefault("width", "20vw")
|
||||
# props.setdefault("height", "100vh")
|
||||
# props.setdefault("position", "fixed")
|
||||
|
||||
return super().create(
|
||||
Box.create(*children, **props), # sidebar for content
|
||||
Box.create(width=props.get("width")), # spacer for layout
|
||||
)
|
||||
|
||||
def _apply_theme(self, theme: Component | None):
|
||||
def add_style(self) -> Style | None:
|
||||
"""Add style to the component.
|
||||
|
||||
Returns:
|
||||
The style of the component.
|
||||
"""
|
||||
sidebar: Component = self.children[-2] # type: ignore
|
||||
spacer: Component = self.children[-1] # type: ignore
|
||||
open = self.State.open if self.State else Var.create("open") # type: ignore
|
||||
sidebar.style["display"] = spacer.style["display"] = cond(open, "block", "none")
|
||||
|
||||
return Style(
|
||||
{
|
||||
"position": "fixed",
|
||||
"border_right": f"1px solid {color('accent', 12)}",
|
||||
"background_color": color("accent", 1),
|
||||
"width": "20vw",
|
||||
"height": "100vh",
|
||||
}
|
||||
)
|
||||
|
||||
def _get_hooks(self) -> Var | None:
|
||||
return hooks.useState("open", "true") if not self.State else None
|
||||
|
||||
|
@ -159,12 +159,17 @@ def format_style_key(key: str) -> Tuple[str, ...]:
|
||||
class Style(dict):
|
||||
"""A style dictionary."""
|
||||
|
||||
def __init__(self, style_dict: dict | None = None):
|
||||
def __init__(self, style_dict: dict | None = None, **kwargs):
|
||||
"""Initialize the style.
|
||||
|
||||
Args:
|
||||
style_dict: The style dictionary.
|
||||
kwargs: Other key value pairs to apply to the dict update.
|
||||
"""
|
||||
if style_dict:
|
||||
style_dict.update(kwargs)
|
||||
else:
|
||||
style_dict = kwargs
|
||||
style_dict, self._var_data = convert(style_dict or {})
|
||||
super().__init__(style_dict)
|
||||
|
||||
|
@ -2,7 +2,7 @@ from typing import Dict, List, Set, Tuple, Union
|
||||
|
||||
import pytest
|
||||
|
||||
from reflex.components import box, foreach, text, theme
|
||||
from reflex.components import box, foreach, text
|
||||
from reflex.components.core import Foreach
|
||||
from reflex.state import BaseState
|
||||
from reflex.vars import Var
|
||||
@ -220,15 +220,6 @@ def test_foreach_render(state_var, render_fn, render_dict):
|
||||
seen_index_vars.add(arg_index._var_name)
|
||||
|
||||
|
||||
def test_foreach_apply_theme():
|
||||
"""Test that the foreach component applies the theme."""
|
||||
tag = Foreach.create(ForEachState.colors_list, display_color) # type: ignore
|
||||
_theme = theme()
|
||||
tag.apply_theme(_theme)
|
||||
assert tag.theme == _theme
|
||||
tag.render()
|
||||
|
||||
|
||||
def test_foreach_bad_annotations():
|
||||
"""Test that the foreach component raises a TypeError if the iterable is of type Any."""
|
||||
with pytest.raises(TypeError):
|
||||
|
@ -1,7 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from reflex.components.lucide.icon import LUCIDE_ICON_LIST, RENAMED_ICONS_05, Icon
|
||||
from reflex.components.radix.themes.base import Theme
|
||||
from reflex.utils import format
|
||||
|
||||
|
||||
@ -17,7 +16,7 @@ RENAMED_TAGS = [tag for tag in RENAMED_ICONS_05.items()]
|
||||
@pytest.mark.parametrize("tag, new_tag", RENAMED_TAGS)
|
||||
def test_icon_renamed_tags(tag, new_tag):
|
||||
Icon.create(tag)
|
||||
# need a PR so we can pass the following test. Currently it fails and uses the old tag as the import.
|
||||
# TODO: need a PR so we can pass the following test. Currently it fails and uses the old tag as the import.
|
||||
# assert icon.alias == f"Lucide{format.to_title_case(new_tag)}Icon"
|
||||
|
||||
|
||||
@ -36,6 +35,6 @@ def test_icon_multiple_children():
|
||||
_ = Icon.create("activity", "child1", "child2")
|
||||
|
||||
|
||||
def test_icon_apply_theme():
|
||||
def test_icon_add_style():
|
||||
ic = Icon.create("activity")
|
||||
ic._apply_theme(Theme())
|
||||
assert ic.add_style() is None
|
||||
|
@ -1,19 +1,21 @@
|
||||
import pytest
|
||||
|
||||
from reflex.components.lucide.icon import Icon
|
||||
from reflex.components.radix.themes.base import Theme
|
||||
from reflex.components.radix.themes.components.icon_button import IconButton
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
|
||||
|
||||
def test_icon_button():
|
||||
ib1 = IconButton.create("activity")
|
||||
ib1._apply_theme(Theme.create())
|
||||
assert isinstance(ib1, IconButton)
|
||||
|
||||
ib2 = IconButton.create(Icon.create("activity"))
|
||||
assert isinstance(ib2, IconButton)
|
||||
|
||||
assert isinstance(ib1.add_style(), Style)
|
||||
assert isinstance(ib2.add_style(), Style)
|
||||
|
||||
|
||||
def test_icon_button_no_child():
|
||||
with pytest.raises(ValueError):
|
||||
|
Loading…
Reference in New Issue
Block a user