Skip to content

Commit 69e4bfe

Browse files
authored
ENG-6162: Switch component (#11)
1 parent d6ed548 commit 69e4bfe

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed

demo/demo/demo.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ def index() -> rx.Component:
2020
on_value_committed=lambda value: rx.toast.success(f"Value: {value}"),
2121
class_name="max-w-xs",
2222
),
23+
ui.switch(
24+
on_checked_change=lambda value: rx.toast.success(f"Value: {value}"),
25+
),
2326
ui.select(
2427
items=[
2528
"Item 1",

reflex_ui/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"components.base.select": ["select"],
1111
"components.base.skeleton": ["skeleton"],
1212
"components.base.slider": ["slider"],
13+
"components.base.switch": ["switch"],
1314
"components.base.theme_switcher": ["theme_switcher"],
1415
}
1516

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""Custom switch component."""
2+
3+
from reflex.components.component import Component, ComponentNamespace
4+
from reflex.event import EventHandler, passthrough_event_spec
5+
from reflex.utils.imports import ImportVar
6+
from reflex.vars import Var
7+
8+
from reflex_ui.components.base_ui import PACKAGE_NAME, BaseUIComponent
9+
10+
11+
class ClassNames:
12+
"""Class names for switch components."""
13+
14+
ROOT = "relative flex h-5 w-8 rounded-full bg-secondary-4 p-0.5 transition-colors duration-200 ease-out before:absolute before:rounded-full before:outline-offset-2 before:outline-primary-8 focus-visible:before:inset-0 data-[checked]:bg-primary-9 disabled:opacity-50 disabled:cursor-not-allowed"
15+
THUMB = "aspect-square h-full rounded-full bg-white transition-transform duration-200 ease-out data-[checked]:translate-x-3 shadow-small"
16+
17+
18+
class SwitchBaseComponent(BaseUIComponent):
19+
"""Base component for switch components."""
20+
21+
library = f"{PACKAGE_NAME}/switch"
22+
23+
@property
24+
def import_var(self):
25+
"""Return the import variable for the switch component."""
26+
return ImportVar(tag="Switch", package_path="", install=False)
27+
28+
29+
class SwitchRoot(SwitchBaseComponent):
30+
"""Represents the switch itself. Renders a button element and a hidden input beside."""
31+
32+
tag = "Switch.Root"
33+
34+
# Identifies the field when a form is submitted.
35+
name: Var[str]
36+
37+
# Whether the switch is initially active. To render a controlled switch, use the checked prop instead. Defaults to False.
38+
default_checked: Var[bool]
39+
40+
# Whether the switch is currently active. To render an uncontrolled switch, use the default_checked prop instead.
41+
checked: Var[bool]
42+
43+
# Event handler called when the switch is activated or deactivated.
44+
on_checked_change: EventHandler[passthrough_event_spec(bool)]
45+
46+
# Whether the component renders a native <button> element when replacing it via the render prop. Set to false if the rendered element is not a button (e.g. <div>). Defaults to True.
47+
native_button: Var[bool]
48+
49+
# Whether the component should ignore user interaction. Defaults to False.
50+
disabled: Var[bool]
51+
52+
# Whether the user should be unable to activate or deactivate the switch. Defaults to False.
53+
read_only: Var[bool]
54+
55+
# Whether the user must activate the switch before submitting a form. Defaults to False.
56+
required: Var[bool]
57+
58+
# A ref to access the hidden <input> element.
59+
input_ref: Var[str]
60+
61+
# The render prop
62+
render_: Var[Component]
63+
64+
@classmethod
65+
def create(cls, *children, **props) -> Component:
66+
"""Create the switch root component."""
67+
cls.set_class_name(ClassNames.ROOT, props)
68+
return super().create(*children, **props)
69+
70+
71+
class SwitchThumb(SwitchBaseComponent):
72+
"""The movable part of the switch that indicates whether the switch is on or off. Renders a span."""
73+
74+
tag = "Switch.Thumb"
75+
76+
# The render prop
77+
render_: Var[Component]
78+
79+
@classmethod
80+
def create(cls, *children, **props) -> Component:
81+
"""Create the switch thumb component."""
82+
cls.set_class_name(ClassNames.THUMB, props)
83+
return super().create(*children, **props)
84+
85+
86+
class HighLevelSwitch(SwitchRoot):
87+
"""High-level wrapper for the Switch component."""
88+
89+
@classmethod
90+
def create(cls, *children, **props) -> Component:
91+
"""Create a complete switch component.
92+
93+
Args:
94+
*children: Additional children to include in the switch.
95+
**props: Additional properties to apply to the switch component.
96+
97+
Returns:
98+
The switch component.
99+
"""
100+
return SwitchRoot.create(
101+
SwitchThumb.create(),
102+
*children,
103+
**props,
104+
)
105+
106+
107+
class Switch(ComponentNamespace):
108+
"""Namespace for Switch components."""
109+
110+
root = staticmethod(SwitchRoot.create)
111+
thumb = staticmethod(SwitchThumb.create)
112+
__call__ = staticmethod(HighLevelSwitch.create)
113+
114+
115+
switch = Switch()

0 commit comments

Comments
 (0)