Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion reflex_ui/components/base/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"outline-shadow",
"secondary",
"ghost",
"ghost-highlight",
"link",
"dark",
]
Expand All @@ -33,9 +34,10 @@
"primary-bordered": "bg-primary-9 text-primary-contrast hover:bg-primary-10 shadow-button-bordered disabled:shadow-none",
"destructive": "bg-destructive-9 hover:bg-destructive-10 text-primary-contrast",
"outline": "border border-secondary-a4 bg-secondary-1 hover:bg-secondary-3 text-secondary-12",
"outline-shadow": "dark:border dark:border-secondary-a4 bg-white dark:bg-secondary-1 hover:bg-secondary-3 text-secondary-12 shadow-button-outline disabled:shadow-none",
"outline-shadow": "dark:shadow-[0_1px_0_0_rgba(255,255,255,0.08)_inset] bg-white hover:bg-secondary-2 dark:bg-secondary-3 dark:hover:bg-secondary-4 text-secondary-12 shadow-button-outline disabled:shadow-none",
"secondary": "bg-secondary-4 text-secondary-12 hover:bg-secondary-5",
"ghost": "hover:bg-secondary-3 text-secondary-11",
"ghost-highlight": "text-secondary-12 hover:text-primary-9",
"link": "text-secondary-12 underline-offset-4 hover:underline",
"dark": "bg-secondary-12 text-secondary-1 hover:bg-secondary-12/80",
},
Expand Down
8 changes: 7 additions & 1 deletion reflex_ui/components/base/button.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ LiteralButtonVariant = Literal[
"outline-shadow",
"secondary",
"ghost",
"ghost-highlight",
"link",
"dark",
]
Expand All @@ -35,9 +36,10 @@ BUTTON_VARIANTS = {
"primary-bordered": "bg-primary-9 text-primary-contrast hover:bg-primary-10 shadow-button-bordered disabled:shadow-none",
"destructive": "bg-destructive-9 hover:bg-destructive-10 text-primary-contrast",
"outline": "border border-secondary-a4 bg-secondary-1 hover:bg-secondary-3 text-secondary-12",
"outline-shadow": "dark:border dark:border-secondary-a4 bg-white dark:bg-secondary-1 hover:bg-secondary-3 text-secondary-12 shadow-button-outline disabled:shadow-none",
"outline-shadow": "dark:shadow-[0_1px_0_0_rgba(255,255,255,0.08)_inset] bg-white hover:bg-secondary-2 dark:bg-secondary-3 dark:hover:bg-secondary-4 text-secondary-12 shadow-button-outline disabled:shadow-none",
"secondary": "bg-secondary-4 text-secondary-12 hover:bg-secondary-5",
"ghost": "hover:bg-secondary-3 text-secondary-11",
"ghost-highlight": "text-secondary-12 hover:text-primary-9",
"link": "text-secondary-12 underline-offset-4 hover:underline",
"dark": "bg-secondary-12 text-secondary-1 hover:bg-secondary-12/80",
},
Expand Down Expand Up @@ -71,6 +73,7 @@ class Button(BaseButton, CoreComponent):
"dark",
"destructive",
"ghost",
"ghost-highlight",
"link",
"outline",
"outline-shadow",
Expand All @@ -83,6 +86,7 @@ class Button(BaseButton, CoreComponent):
"dark",
"destructive",
"ghost",
"ghost-highlight",
"link",
"outline",
"outline-shadow",
Expand Down Expand Up @@ -359,6 +363,7 @@ class ButtonNamespace(ComponentNamespace):
"dark",
"destructive",
"ghost",
"ghost-highlight",
"link",
"outline",
"outline-shadow",
Expand All @@ -371,6 +376,7 @@ class ButtonNamespace(ComponentNamespace):
"dark",
"destructive",
"ghost",
"ghost-highlight",
"link",
"outline",
"outline-shadow",
Expand Down
17 changes: 9 additions & 8 deletions reflex_ui/components/base/input.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Custom input component."""

from typing import Literal
from typing import ClassVar, Literal

from reflex.components.component import Component, ComponentNamespace
from reflex.components.el import Button, Div, Span
Expand All @@ -17,7 +17,7 @@
"xs": "px-1.5 h-7 rounded-ui-xs gap-1.5",
"sm": "px-2 h-8 rounded-ui-sm gap-2",
"md": "px-2.5 h-9 rounded-ui-md gap-2",
"lg": "px-3 h-10 rounded-lg gap-2.5",
"lg": "px-3 h-10 rounded-ui-lg gap-2.5",
"xl": "px-3.5 h-12 rounded-ui-xl gap-3",
}

Expand All @@ -34,8 +34,8 @@
class ClassNames:
"""Class names for input components."""

INPUT = "outline-none bg-transparent text-secondary-12 placeholder:text-secondary-9 text-sm leading-normal peer disabled:text-secondary-8 disabled:placeholder:text-secondary-8 w-full data-[disabled]:pointer-events-none font-medium"
DIV = "flex flex-row items-center focus-within:shadow-[0px_0px_0px_2px_var(--primary-4)] focus-within:border-primary-a6 not-data-[invalid]:focus-within:hover:border-primary-a6 bg-secondary-1 shrink-0 border border-secondary-a4 hover:border-secondary-a6 transition-[color,box-shadow] text-secondary-9 [&_svg]:pointer-events-none has-data-[disabled]:border-secondary-4 has-data-[disabled]:bg-secondary-3 has-data-[disabled]:text-secondary-8 has-data-[disabled]:cursor-not-allowed cursor-text has-data-[invalid]:border-destructive-10 has-data-[invalid]:focus-within:border-destructive-a11 has-data-[invalid]:focus-within:shadow-[0px_0px_0px_2px_var(--destructive-4)] has-data-[invalid]:hover:border-destructive-a11"
INPUT = "outline-none bg-transparent text-secondary-12 placeholder:text-secondary-10 text-sm leading-normal peer disabled:text-secondary-8 disabled:placeholder:text-secondary-8 w-full data-[disabled]:pointer-events-none font-medium"
DIV = "flex flex-row items-center focus-within:shadow-[0px_0px_0px_2px_var(--primary-4)] focus-within:border-primary-a6 not-data-[invalid]:focus-within:hover:border-primary-a6 bg-white dark:bg-secondary-3 shrink-0 border border-secondary-4 hover:border-secondary-a6 transition-[color,box-shadow] text-secondary-9 [&_svg]:pointer-events-none has-data-[disabled]:border-secondary-4 has-data-[disabled]:bg-secondary-3 has-data-[disabled]:text-secondary-8 has-data-[disabled]:cursor-not-allowed cursor-text has-data-[invalid]:border-destructive-10 has-data-[invalid]:focus-within:border-destructive-a11 has-data-[invalid]:focus-within:shadow-[0px_0px_0px_2px_var(--destructive-4)] has-data-[invalid]:hover:border-destructive-a11 shadow-[0_1px_2px_0_rgba(0,0,0,0.02),0_1px_4px_0_rgba(0,0,0,0.02)] dark:shadow-none dark:border-secondary-5"


class InputBaseComponent(BaseUIComponent):
Expand Down Expand Up @@ -74,7 +74,7 @@ class HighLevelInput(InputBaseComponent):
icon: Var[str]

# Whether to show the clear button.
show_clear_button: Var[bool]
show_clear_button: ClassVar[bool]

# Events to fire when the clear button is clicked.
clear_events: Var[list[EventHandler]]
Expand Down Expand Up @@ -132,20 +132,21 @@ def create(cls, *children, **props) -> BaseUIComponent:
show_clear_button = props.pop("show_clear_button", True)
clear_events = props.pop("clear_events", [])
# Configure input with merged attributes
custom_attrs_override = props.pop("custom_attrs", {})
input_props.update(
{
"id": id,
"custom_attrs": {
**DEFAULT_INPUT_ATTRS,
**input_props.get("custom_attrs", {}),
**custom_attrs_override,
},
}
)

return Div.create( # pyright: ignore[reportReturnType]
(
Span.create(
hi(icon, class_name="text-secondary-9 size-4 pointer-events-none"),
hi(icon, class_name="text-secondary-12 size-4 pointer-events-none"),
aria_hidden="true",
)
if icon
Expand All @@ -171,7 +172,7 @@ def _create_clear_button(id: str, clear_events: list[EventHandler]) -> Button:
*clear_events,
],
tab_index=-1,
class_name="opacity-100 peer-placeholder-shown:opacity-0 hover:text-secondary-12 transition-colors peer-placeholder-shown:pointer-events-none peer-disabled:pointer-events-none peer-disabled:opacity-0 h-full",
class_name="opacity-100 peer-placeholder-shown:opacity-0 hover:text-secondary-12 transition-colors peer-placeholder-shown:pointer-events-none peer-disabled:pointer-events-none peer-disabled:opacity-0 h-full text-secondary-11",
)

def _exclude_props(self) -> list[str]:
Expand Down
14 changes: 8 additions & 6 deletions reflex_ui/components/base/input.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------
from collections.abc import Mapping, Sequence
from typing import Any, Literal
from typing import Any, ClassVar, Literal

from reflex.components.component import Component, ComponentNamespace
from reflex.components.core.breakpoints import Breakpoints
Expand All @@ -18,7 +18,7 @@ INPUT_SIZE_VARIANTS = {
"xs": "px-1.5 h-7 rounded-ui-xs gap-1.5",
"sm": "px-2 h-8 rounded-ui-sm gap-2",
"md": "px-2.5 h-9 rounded-ui-md gap-2",
"lg": "px-3 h-10 rounded-lg gap-2.5",
"lg": "px-3 h-10 rounded-ui-lg gap-2.5",
"xl": "px-3.5 h-12 rounded-ui-xl gap-3",
}
LiteralControlSize = Literal["xs", "sm", "md", "lg", "xl"]
Expand All @@ -30,8 +30,8 @@ DEFAULT_INPUT_ATTRS = {
}

class ClassNames:
INPUT = "outline-none bg-transparent text-secondary-12 placeholder:text-secondary-9 text-sm leading-normal peer disabled:text-secondary-8 disabled:placeholder:text-secondary-8 w-full data-[disabled]:pointer-events-none font-medium"
DIV = "flex flex-row items-center focus-within:shadow-[0px_0px_0px_2px_var(--primary-4)] focus-within:border-primary-a6 not-data-[invalid]:focus-within:hover:border-primary-a6 bg-secondary-1 shrink-0 border border-secondary-a4 hover:border-secondary-a6 transition-[color,box-shadow] text-secondary-9 [&_svg]:pointer-events-none has-data-[disabled]:border-secondary-4 has-data-[disabled]:bg-secondary-3 has-data-[disabled]:text-secondary-8 has-data-[disabled]:cursor-not-allowed cursor-text has-data-[invalid]:border-destructive-10 has-data-[invalid]:focus-within:border-destructive-a11 has-data-[invalid]:focus-within:shadow-[0px_0px_0px_2px_var(--destructive-4)] has-data-[invalid]:hover:border-destructive-a11"
INPUT = "outline-none bg-transparent text-secondary-12 placeholder:text-secondary-10 text-sm leading-normal peer disabled:text-secondary-8 disabled:placeholder:text-secondary-8 w-full data-[disabled]:pointer-events-none font-medium"
DIV = "flex flex-row items-center focus-within:shadow-[0px_0px_0px_2px_var(--primary-4)] focus-within:border-primary-a6 not-data-[invalid]:focus-within:hover:border-primary-a6 bg-white dark:bg-secondary-3 shrink-0 border border-secondary-4 hover:border-secondary-a6 transition-[color,box-shadow] text-secondary-9 [&_svg]:pointer-events-none has-data-[disabled]:border-secondary-4 has-data-[disabled]:bg-secondary-3 has-data-[disabled]:text-secondary-8 has-data-[disabled]:cursor-not-allowed cursor-text has-data-[invalid]:border-destructive-10 has-data-[invalid]:focus-within:border-destructive-a11 has-data-[invalid]:focus-within:shadow-[0px_0px_0px_2px_var(--destructive-4)] has-data-[invalid]:hover:border-destructive-a11 shadow-[0_1px_2px_0_rgba(0,0,0,0.02),0_1px_4px_0_rgba(0,0,0,0.02)] dark:shadow-none dark:border-secondary-5"

class InputBaseComponent(BaseUIComponent):
@property
Expand Down Expand Up @@ -400,6 +400,8 @@ class InputRoot(InputBaseComponent, ReflexInput):
"""Create a high level input component with simplified API."""

class HighLevelInput(InputBaseComponent):
show_clear_button: ClassVar[bool]

@classmethod
def create(
cls,
Expand All @@ -408,7 +410,7 @@ class HighLevelInput(InputBaseComponent):
| Var[Literal["lg", "md", "sm", "xl", "xs"]]
| None = None,
icon: Var[str] | str | None = None,
show_clear_button: Var[bool] | bool | None = None,
show_clear_button: ClassVar[bool] | None = None,
clear_events: Var[list[EventHandler]] | list[EventHandler] | None = None,
unstyled: Var[bool] | bool | None = None,
style: Sequence[Mapping[str, Any]]
Expand Down Expand Up @@ -452,7 +454,7 @@ class Input(ComponentNamespace):
| Var[Literal["lg", "md", "sm", "xl", "xs"]]
| None = None,
icon: Var[str] | str | None = None,
show_clear_button: Var[bool] | bool | None = None,
show_clear_button: ClassVar[bool] | None = None,
clear_events: Var[list[EventHandler]] | list[EventHandler] | None = None,
unstyled: Var[bool] | bool | None = None,
style: Sequence[Mapping[str, Any]]
Expand Down
71 changes: 62 additions & 9 deletions reflex_ui/components/base/tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,34 @@
from reflex_ui.components.base_ui import PACKAGE_NAME, BaseUIComponent

LiteralOrientation = Literal["horizontal", "vertical"]
LiteralTabsSize = Literal["sm", "md", "lg"]


class ClassNames:
"""Class names for tabs components."""

ROOT = "flex flex-col gap-2"
LIST = "bg-secondary-3 inline-flex gap-1 p-1 items-center justify-start rounded-ui-md relative z-0"
TAB = "h-7 px-1.5 rounded-ui-sm justify-center items-center gap-1.5 inline-flex text-sm font-medium text-secondary-11 cursor-pointer z-[1] hover:text-secondary-12 transition-color text-nowrap data-[active]:text-secondary-12 data-[disabled]:cursor-not-allowed data-[disabled]:text-secondary-8"
INDICATOR = "absolute top-1/2 left-0 -z-1 h-7 w-(--active-tab-width) -translate-y-1/2 translate-x-(--active-tab-left) rounded-ui-sm bg-secondary-1 shadow-small transition-all duration-200 ease-in-out"
LIST = "bg-secondary-1 inline-flex items-center justify-start relative z-0 shadow-button-outline dark:border dark:border-secondary-4"
TAB = "justify-center items-center inline-flex font-medium text-secondary-11 cursor-pointer z-[1] hover:text-primary-9 transition-color text-nowrap data-[active]:text-secondary-12 data-[disabled]:cursor-not-allowed data-[disabled]:text-secondary-8 text-sm"
INDICATOR = "absolute left-0 inset-y-0 my-0.5 -z-1 w-(--active-tab-width) translate-x-(--active-tab-left) transition-all duration-200 ease-in-out dark:shadow-[0_1px_0_0_rgba(255,255,255,0.08)_inset] bg-white dark:bg-secondary-3 text-secondary-12 shadow-button-outline"
PANEL = "flex flex-col gap-2"
SIZES = {
"list": {
"sm": "p-0.5 rounded-ui-md gap-0.5",
"md": "p-0.5 rounded-ui-md gap-0.5",
"lg": "p-0.5 rounded-ui-md gap-0.5",
},
"tab": {
"sm": "h-7 px-1.5 rounded-ui-sm gap-1",
"md": "h-8 px-2 rounded-ui-sm gap-1.5",
"lg": "h-9 px-2.5 rounded-ui-sm gap-2",
},
"indicator": {
"sm": "rounded-ui-sm",
"md": "rounded-ui-sm",
"lg": "rounded-ui-sm",
},
}


class TabsBaseComponent(BaseUIComponent):
Expand Down Expand Up @@ -72,13 +90,24 @@ class TabsList(TabsBaseComponent):
# Whether to loop keyboard focus back to the first item when the end of the list is reached while using the arrow keys. Defaults to True.
loop_focus: Var[bool]

# The size of the tabs list. Defaults to "sm".
size: Var[LiteralTabsSize]

@classmethod
def create(cls, *children, **props) -> BaseUIComponent:
"""Create the tabs list component."""
"""Create the tabs list component.

Returns:
The component.
"""
size = props.pop("size", "sm")
props["data-slot"] = "tabs-list"
cls.set_class_name(ClassNames.LIST, props)
cls.set_class_name(f"{ClassNames.LIST} {ClassNames.SIZES['list'][size]}", props)
return super().create(*children, **props)

def _exclude_props(self) -> list[str]:
return [*super()._exclude_props(), "size"]


class TabsTab(TabsBaseComponent):
"""An individual interactive tab button that toggles the corresponding panel. Renders a <button> element."""
Expand All @@ -97,13 +126,24 @@ class TabsTab(TabsBaseComponent):
# The render prop
render_: Var[Component]

# The size of the tab. Defaults to "sm".
size: Var[LiteralTabsSize]

@classmethod
def create(cls, *children, **props) -> BaseUIComponent:
"""Create the tabs tab component."""
"""Create the tabs tab component.

Returns:
The component.
"""
size = props.pop("size", "sm")
props["data-slot"] = "tabs-tab"
cls.set_class_name(ClassNames.TAB, props)
cls.set_class_name(f"{ClassNames.TAB} {ClassNames.SIZES['tab'][size]}", props)
return super().create(*children, **props)

def _exclude_props(self) -> list[str]:
return [*super()._exclude_props(), "size"]


class TabsIndicator(TabsBaseComponent):
"""A visual indicator that can be styled to match the position of the currently active tab. Renders a <span> element."""
Expand All @@ -116,13 +156,26 @@ class TabsIndicator(TabsBaseComponent):
# The render prop
render_: Var[Component]

# The size of the indicator. Defaults to "sm".
size: Var[LiteralTabsSize]

@classmethod
def create(cls, *children, **props) -> BaseUIComponent:
"""Create the tabs indicator component."""
"""Create the tabs indicator component.

Returns:
The component.
"""
size = props.pop("size", "sm")
props["data-slot"] = "tabs-indicator"
cls.set_class_name(ClassNames.INDICATOR, props)
cls.set_class_name(
f"{ClassNames.INDICATOR} {ClassNames.SIZES['indicator'][size]}", props
)
return super().create(*children, **props)

def _exclude_props(self) -> list[str]:
return [*super()._exclude_props(), "size"]


class TabsPanel(TabsBaseComponent):
"""A panel displayed when the corresponding tab is active. Renders a <div> element."""
Expand Down
Loading
Loading