Merge remote-tracking branch 'origin/main' into reflex-0.4.0

This commit is contained in:
Masen Furer 2024-02-08 10:17:34 -08:00
commit ae20644a82
No known key found for this signature in database
GPG Key ID: B0008AD22B3B3A95
28 changed files with 373 additions and 191 deletions

View File

@ -1,5 +1,6 @@
"""Test state inheritance."""
import time
from typing import Generator
import pytest
@ -8,30 +9,57 @@ from selenium.webdriver.common.by import By
from reflex.testing import DEFAULT_TIMEOUT, AppHarness, WebDriver
def raises_alert(driver: WebDriver, element: str) -> None:
"""Click an element and check that an alert is raised.
Args:
driver: WebDriver instance.
element: The element to click.
"""
btn = driver.find_element(By.ID, element)
btn.click()
time.sleep(0.2) # wait for the alert to appear
alert = driver.switch_to.alert
assert alert.text == "clicked"
alert.accept()
def StateInheritance():
"""Test that state inheritance works as expected."""
import reflex as rx
class ChildMixin:
child_mixin: str = "child_mixin"
# mixin basevars only work with pydantic/rx.Base models
# child_mixin: str = "child_mixin"
@rx.var
def computed_child_mixin(self) -> str:
return "computed_child_mixin"
class Mixin(ChildMixin):
mixin: str = "mixin"
# mixin basevars only work with pydantic/rx.Base models
# mixin: str = "mixin"
@rx.var
def computed_mixin(self) -> str:
return "computed_mixin"
def on_click_mixin(self):
return rx.call_script("alert('clicked')")
class OtherMixin(rx.Base):
other_mixin: str = "other_mixin"
other_mixin_clicks: int = 0
@rx.var
def computed_other_mixin(self) -> str:
return "computed_other_mixin"
return self.other_mixin
def on_click_other_mixin(self):
self.other_mixin_clicks += 1
self.other_mixin = (
f"{self.__class__.__name__}.clicked.{self.other_mixin_clicks}"
)
class Base1(rx.State, Mixin):
base1: str = "base1"
@ -65,30 +93,49 @@ def StateInheritance():
rx.chakra.input(
id="token", value=Base1.router.session.client_token, is_read_only=True
),
# Base 1
rx.heading(Base1.computed_mixin, id="base1-computed_mixin"),
rx.heading(Base1.computed_basevar, id="base1-computed_basevar"),
rx.heading(Base1.computed_child_mixin, id="base1-child-mixin"),
rx.heading(Base1.base1, id="base1-base1"),
rx.heading(Base1.mixin, id="base1-mixin"),
rx.heading(Base1.child_mixin, id="base1-child_mixin"),
rx.button(
"Base1.on_click_mixin",
on_click=Base1.on_click_mixin, # type: ignore
id="base1-mixin-btn",
),
# Base 2
rx.heading(Base2.computed_basevar, id="base2-computed_basevar"),
rx.heading(Base2.base2, id="base2-base2"),
# Child 1
rx.heading(Child1.computed_basevar, id="child1-computed_basevar"),
rx.heading(Child1.computed_mixin, id="child1-computed_mixin"),
rx.heading(Child1.computed_other_mixin, id="child1-other-mixin"),
rx.heading(Child1.computed_child_mixin, id="child1-child-mixin"),
rx.heading(Child1.base1, id="child1-base1"),
rx.heading(Child1.mixin, id="child1-mixin"),
rx.heading(Child1.other_mixin, id="child1-other_mixin"),
rx.heading(Child1.child_mixin, id="child1-child_mixin"),
rx.button(
"Child1.on_click_other_mixin",
on_click=Child1.on_click_other_mixin, # type: ignore
id="child1-other-mixin-btn",
),
# Child 2
rx.heading(Child2.computed_basevar, id="child2-computed_basevar"),
rx.heading(Child2.computed_mixin, id="child2-computed_mixin"),
rx.heading(Child2.computed_other_mixin, id="child2-other-mixin"),
rx.heading(Child2.computed_child_mixin, id="child2-child-mixin"),
rx.heading(Child2.base2, id="child2-base2"),
rx.heading(Child2.mixin, id="child2-mixin"),
rx.heading(Child2.other_mixin, id="child2-other_mixin"),
rx.heading(Child2.child_mixin, id="child2-child_mixin"),
rx.button(
"Child2.on_click_mixin",
on_click=Child2.on_click_mixin, # type: ignore
id="child2-mixin-btn",
),
rx.button(
"Child2.on_click_other_mixin",
on_click=Child2.on_click_other_mixin, # type: ignore
id="child2-other-mixin-btn",
),
# Child 3
rx.heading(Child3.computed_basevar, id="child3-computed_basevar"),
rx.heading(Child3.computed_mixin, id="child3-computed_mixin"),
rx.heading(Child3.computed_other_mixin, id="child3-other-mixin"),
@ -96,9 +143,17 @@ def StateInheritance():
rx.heading(Child3.computed_child_mixin, id="child3-child-mixin"),
rx.heading(Child3.child3, id="child3-child3"),
rx.heading(Child3.base2, id="child3-base2"),
rx.heading(Child3.mixin, id="child3-mixin"),
rx.heading(Child3.other_mixin, id="child3-other_mixin"),
rx.heading(Child3.child_mixin, id="child3-child_mixin"),
rx.button(
"Child3.on_click_mixin",
on_click=Child3.on_click_mixin, # type: ignore
id="child3-mixin-btn",
),
rx.button(
"Child3.on_click_other_mixin",
on_click=Child3.on_click_other_mixin, # type: ignore
id="child3-other-mixin-btn",
),
)
app = rx.App()
@ -178,6 +233,8 @@ def test_state_inheritance(
"""
assert state_inheritance.app_instance is not None
# Initial State values Test
# Base 1
base1_mixin = driver.find_element(By.ID, "base1-computed_mixin")
assert base1_mixin.text == "computed_mixin"
@ -190,18 +247,14 @@ def test_state_inheritance(
base1_base1 = driver.find_element(By.ID, "base1-base1")
assert base1_base1.text == "base1"
base1_mixin = driver.find_element(By.ID, "base1-mixin")
assert base1_mixin.text == "mixin"
base1_child_mixin = driver.find_element(By.ID, "base1-child_mixin")
assert base1_child_mixin.text == "child_mixin"
# Base 2
base2_computed_basevar = driver.find_element(By.ID, "base2-computed_basevar")
assert base2_computed_basevar.text == "computed_basevar2"
base2_base2 = driver.find_element(By.ID, "base2-base2")
assert base2_base2.text == "base2"
# Child 1
child1_computed_basevar = driver.find_element(By.ID, "child1-computed_basevar")
assert child1_computed_basevar.text == "computed_basevar1"
@ -209,7 +262,7 @@ def test_state_inheritance(
assert child1_mixin.text == "computed_mixin"
child1_computed_other_mixin = driver.find_element(By.ID, "child1-other-mixin")
assert child1_computed_other_mixin.text == "computed_other_mixin"
assert child1_computed_other_mixin.text == "other_mixin"
child1_computed_child_mixin = driver.find_element(By.ID, "child1-child-mixin")
assert child1_computed_child_mixin.text == "computed_child_mixin"
@ -217,15 +270,10 @@ def test_state_inheritance(
child1_base1 = driver.find_element(By.ID, "child1-base1")
assert child1_base1.text == "base1"
child1_mixin = driver.find_element(By.ID, "child1-mixin")
assert child1_mixin.text == "mixin"
child1_other_mixin = driver.find_element(By.ID, "child1-other_mixin")
assert child1_other_mixin.text == "other_mixin"
child1_child_mixin = driver.find_element(By.ID, "child1-child_mixin")
assert child1_child_mixin.text == "child_mixin"
# Child 2
child2_computed_basevar = driver.find_element(By.ID, "child2-computed_basevar")
assert child2_computed_basevar.text == "computed_basevar2"
@ -233,7 +281,7 @@ def test_state_inheritance(
assert child2_mixin.text == "computed_mixin"
child2_computed_other_mixin = driver.find_element(By.ID, "child2-other-mixin")
assert child2_computed_other_mixin.text == "computed_other_mixin"
assert child2_computed_other_mixin.text == "other_mixin"
child2_computed_child_mixin = driver.find_element(By.ID, "child2-child-mixin")
assert child2_computed_child_mixin.text == "computed_child_mixin"
@ -241,15 +289,10 @@ def test_state_inheritance(
child2_base2 = driver.find_element(By.ID, "child2-base2")
assert child2_base2.text == "base2"
child2_mixin = driver.find_element(By.ID, "child2-mixin")
assert child2_mixin.text == "mixin"
child2_other_mixin = driver.find_element(By.ID, "child2-other_mixin")
assert child2_other_mixin.text == "other_mixin"
child2_child_mixin = driver.find_element(By.ID, "child2-child_mixin")
assert child2_child_mixin.text == "child_mixin"
# Child 3
child3_computed_basevar = driver.find_element(By.ID, "child3-computed_basevar")
assert child3_computed_basevar.text == "computed_basevar2"
@ -257,7 +300,7 @@ def test_state_inheritance(
assert child3_mixin.text == "computed_mixin"
child3_computed_other_mixin = driver.find_element(By.ID, "child3-other-mixin")
assert child3_computed_other_mixin.text == "computed_other_mixin"
assert child3_computed_other_mixin.text == "other_mixin"
child3_computed_childvar = driver.find_element(By.ID, "child3-computed_childvar")
assert child3_computed_childvar.text == "computed_childvar"
@ -271,11 +314,59 @@ def test_state_inheritance(
child3_base2 = driver.find_element(By.ID, "child3-base2")
assert child3_base2.text == "base2"
child3_mixin = driver.find_element(By.ID, "child3-mixin")
assert child3_mixin.text == "mixin"
child3_other_mixin = driver.find_element(By.ID, "child3-other_mixin")
assert child3_other_mixin.text == "other_mixin"
child3_child_mixin = driver.find_element(By.ID, "child3-child_mixin")
assert child3_child_mixin.text == "child_mixin"
# Event Handler Tests
raises_alert(driver, "base1-mixin-btn")
raises_alert(driver, "child2-mixin-btn")
raises_alert(driver, "child3-mixin-btn")
child1_other_mixin_btn = driver.find_element(By.ID, "child1-other-mixin-btn")
child1_other_mixin_btn.click()
child1_other_mixin_value = state_inheritance.poll_for_content(
child1_other_mixin, exp_not_equal="other_mixin"
)
child1_computed_mixin_value = state_inheritance.poll_for_content(
child1_computed_other_mixin, exp_not_equal="other_mixin"
)
assert child1_other_mixin_value == "Child1.clicked.1"
assert child1_computed_mixin_value == "Child1.clicked.1"
child2_other_mixin_btn = driver.find_element(By.ID, "child2-other-mixin-btn")
child2_other_mixin_btn.click()
child2_other_mixin_value = state_inheritance.poll_for_content(
child2_other_mixin, exp_not_equal="other_mixin"
)
child2_computed_mixin_value = state_inheritance.poll_for_content(
child2_computed_other_mixin, exp_not_equal="other_mixin"
)
child3_other_mixin_value = state_inheritance.poll_for_content(
child3_other_mixin, exp_not_equal="other_mixin"
)
child3_computed_mixin_value = state_inheritance.poll_for_content(
child3_computed_other_mixin, exp_not_equal="other_mixin"
)
assert child2_other_mixin_value == "Child2.clicked.1"
assert child2_computed_mixin_value == "Child2.clicked.1"
assert child3_other_mixin_value == "Child2.clicked.1"
assert child3_computed_mixin_value == "Child2.clicked.1"
child3_other_mixin_btn = driver.find_element(By.ID, "child3-other-mixin-btn")
child3_other_mixin_btn.click()
child2_other_mixin_value = state_inheritance.poll_for_content(
child2_other_mixin, exp_not_equal="other_mixin"
)
child2_computed_mixin_value = state_inheritance.poll_for_content(
child2_computed_other_mixin, exp_not_equal="other_mixin"
)
child3_other_mixin_value = state_inheritance.poll_for_content(
child3_other_mixin, exp_not_equal="other_mixin"
)
child3_computed_mixin_value = state_inheritance.poll_for_content(
child3_computed_other_mixin, exp_not_equal="other_mixin"
)
assert child2_other_mixin_value == "Child2.clicked.2"
assert child2_computed_mixin_value == "Child2.clicked.2"
assert child3_other_mixin.text == "Child2.clicked.2"
assert child3_computed_other_mixin.text == "Child2.clicked.2"

View File

@ -2,7 +2,7 @@
import axios from "axios";
import io from "socket.io-client";
import JSON5 from "json5";
import env from "env.json";
import env from "/env.json";
import Cookies from "universal-cookie";
import { useEffect, useReducer, useRef, useState } from "react";
import Router, { useRouter } from "next/router";
@ -74,18 +74,23 @@ export const getToken = () => {
};
/**
* Get the URL for the websocket connection
* @returns The websocket URL object.
* Get the URL for the backend server
* @param url_str The URL string to parse.
* @returns The given URL modified to point to the actual backend server.
*/
export const getEventURL = () => {
export const getBackendURL = (url_str) => {
// Get backend URL object from the endpoint.
const endpoint = new URL(EVENTURL);
const endpoint = new URL(url_str);
if (SAME_DOMAIN_HOSTNAMES.includes(endpoint.hostname)) {
// Use the frontend domain to access the backend
const frontend_hostname = window.location.hostname;
endpoint.hostname = frontend_hostname;
if (window.location.protocol === "https:" && endpoint.protocol === "ws:") {
endpoint.protocol = "wss:";
if (window.location.protocol === "https:") {
if (endpoint.protocol === "ws:") {
endpoint.protocol = "wss:";
} else if (endpoint.protocol === "http:") {
endpoint.protocol = "https:";
}
endpoint.port = ""; // Assume websocket is on https port via load balancer.
}
}
@ -296,7 +301,7 @@ export const connect = async (
client_storage = {},
) => {
// Get backend URL object from the endpoint.
const endpoint = getEventURL()
const endpoint = getBackendURL(EVENTURL)
// Create the socket.
socket.current = io(endpoint.href, {
@ -397,7 +402,7 @@ export const uploadFiles = async (handler, files, upload_id, on_upload_progress,
upload_controllers[upload_id] = controller
try {
return await axios.post(UPLOADURL, formdata, config)
return await axios.post(getBackendURL(UPLOADURL), formdata, config)
} catch (error) {
if (error.response) {
// The request was made and the server responded with a status code

View File

@ -17,7 +17,7 @@ class Button(BaseHTML):
auto_focus: Var[Union[str, int, bool]]
# Disables the button
disabled: Var[Union[str, int, bool]]
disabled: Var[bool]
# Associates the button with a form (by id)
form: Var[Union[str, int, bool]]

View File

@ -22,9 +22,7 @@ class Button(BaseHTML):
auto_focus: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
disabled: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
disabled: Optional[Union[Var[bool], bool]] = None,
form: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
form_action: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]

View File

@ -6,9 +6,9 @@ from reflex import el
from reflex.constants import EventTriggers
from reflex.vars import Var
from ..base import LiteralSize, RadixThemesComponent
from ..base import RadixThemesComponent
LiteralSwitchSize = Literal["1", "2", "3", "4"]
LiteralContentSize = Literal["1", "2", "3", "4"]
class AlertDialogRoot(RadixThemesComponent):
@ -43,7 +43,7 @@ class AlertDialogContent(el.Div, RadixThemesComponent):
tag = "AlertDialog.Content"
# The size of the content.
size: Var[LiteralSize]
size: Var[LiteralContentSize]
# Whether to force mount the content on open.
force_mount: Var[bool]

View File

@ -12,9 +12,9 @@ from typing import Any, Dict, Literal
from reflex import el
from reflex.constants import EventTriggers
from reflex.vars import Var
from ..base import LiteralSize, RadixThemesComponent
from ..base import RadixThemesComponent
LiteralSwitchSize = Literal["1", "2", "3", "4"]
LiteralContentSize = Literal["1", "2", "3", "4"]
class AlertDialogRoot(RadixThemesComponent):
def get_event_triggers(self) -> Dict[str, Any]: ...
@ -385,10 +385,7 @@ class AlertDialogContent(el.Div, RadixThemesComponent):
]
] = None,
size: Optional[
Union[
Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
]
Union[Var[Literal["1", "2", "3", "4"]], Literal["1", "2", "3", "4"]]
] = None,
force_mount: Optional[Union[Var[bool], bool]] = None,
access_key: Optional[

View File

@ -108,9 +108,7 @@ class Button(el.Button, RadixThemesComponent):
auto_focus: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
disabled: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
disabled: Optional[Union[Var[bool], bool]] = None,
form: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
form_action: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]

View File

@ -49,7 +49,7 @@ class DialogContent(el.Div, RadixThemesComponent):
tag = "Dialog.Content"
# DialogContent size "1" - "4"
size: Var[Literal[1, 2, 3, 4]]
size: Var[Literal["1", "2", "3", "4"]]
def get_event_triggers(self) -> Dict[str, Any]:
"""Get the events triggers signatures for the component.

View File

@ -528,7 +528,9 @@ class DialogContent(el.Div, RadixThemesComponent):
],
]
] = None,
size: Optional[Union[Var[Literal[1, 2, 3, 4]], Literal[1, 2, 3, 4]]] = None,
size: Optional[
Union[Var[Literal["1", "2", "3", "4"]], Literal["1", "2", "3", "4"]]
] = None,
access_key: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,

View File

@ -111,9 +111,7 @@ class IconButton(el.Button, RadixThemesComponent):
auto_focus: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
disabled: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
disabled: Optional[Union[Var[bool], bool]] = None,
form: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
form_action: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]

View File

@ -46,7 +46,7 @@ class PopoverContent(el.Div, RadixThemesComponent):
tag = "Popover.Content"
# Size of the button: "1" | "2" | "3" | "4"
size: Var[Literal[1, 2, 3, 4]]
size: Var[Literal["1", "2", "3", "4"]]
# The preferred side of the anchor to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled.
side: Var[Literal["top", "right", "bottom", "left"]]

View File

@ -384,7 +384,9 @@ class PopoverContent(el.Div, RadixThemesComponent):
],
]
] = None,
size: Optional[Union[Var[Literal[1, 2, 3, 4]], Literal[1, 2, 3, 4]]] = None,
size: Optional[
Union[Var[Literal["1", "2", "3", "4"]], Literal["1", "2", "3", "4"]]
] = None,
side: Optional[
Union[
Var[Literal["top", "right", "bottom", "left"]],

View File

@ -50,12 +50,6 @@ class RadioGroupRoot(RadixThemesComponent):
# Whether the radio group is required
required: Var[bool]
# The orientation of the component.
orientation: Var[Literal["horizontal", "vertical"]]
# When true, keyboard navigation will loop from last item to first, and vice versa.
loop: Var[bool]
# Props to rename
_rename_props = {"onChange": "onValueChange"}
@ -86,7 +80,7 @@ class RadioGroupItem(RadixThemesComponent):
required: Var[bool]
class HighLevelRadioGroup(RadioGroupRoot):
class HighLevelRadioGroup(RadixThemesComponent):
"""High level wrapper for the RadioGroup component."""
# The items of the radio group.
@ -101,6 +95,33 @@ class HighLevelRadioGroup(RadioGroupRoot):
# The size of the radio group.
size: Var[Literal["1", "2", "3"]] = Var.create_safe("2")
# The variant of the radio group
variant: Var[Literal["classic", "surface", "soft"]]
# The color of the radio group
color_scheme: Var[LiteralAccentColor]
# Whether to render the radio group with higher contrast color against background
high_contrast: Var[bool]
# The controlled value of the radio item to check. Should be used in conjunction with on_change.
value: Var[str]
# The initial value of checked radio item. Should be used in conjunction with on_change.
default_value: Var[str]
# Whether the radio group is disabled
disabled: Var[bool]
# The name of the group. Submitted with its owning form as part of a name/value pair.
name: Var[str]
# Whether the radio group is required
required: Var[bool]
# Props to rename
_rename_props = {"onChange": "onValueChange"}
@classmethod
def create(
cls,

View File

@ -104,13 +104,6 @@ class RadioGroupRoot(RadixThemesComponent):
disabled: Optional[Union[Var[bool], bool]] = None,
name: Optional[Union[Var[str], str]] = None,
required: Optional[Union[Var[bool], bool]] = None,
orientation: Optional[
Union[
Var[Literal["horizontal", "vertical"]],
Literal["horizontal", "vertical"],
]
] = None,
loop: Optional[Union[Var[bool], bool]] = None,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
@ -185,8 +178,6 @@ class RadioGroupRoot(RadixThemesComponent):
disabled: Whether the radio group is disabled
name: The name of the group. Submitted with its owning form as part of a name/value pair.
required: Whether the radio group is required
orientation: The orientation of the component.
loop: When true, keyboard navigation will loop from last item to first, and vice versa.
style: Props to rename The style of the component.
key: A unique key for the component.
id: The id for the component.
@ -353,7 +344,7 @@ class RadioGroupItem(RadixThemesComponent):
"""
...
class HighLevelRadioGroup(RadioGroupRoot):
class HighLevelRadioGroup(RadixThemesComponent):
@overload
@classmethod
def create( # type: ignore
@ -449,13 +440,6 @@ class HighLevelRadioGroup(RadioGroupRoot):
disabled: Optional[Union[Var[bool], bool]] = None,
name: Optional[Union[Var[str], str]] = None,
required: Optional[Union[Var[bool], bool]] = None,
orientation: Optional[
Union[
Var[Literal["horizontal", "vertical"]],
Literal["horizontal", "vertical"],
]
] = None,
loop: Optional[Union[Var[bool], bool]] = None,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
@ -466,9 +450,6 @@ class HighLevelRadioGroup(RadioGroupRoot):
on_blur: Optional[
Union[EventHandler, EventSpec, list, function, BaseVar]
] = None,
on_change: Optional[
Union[EventHandler, EventSpec, list, function, BaseVar]
] = None,
on_click: Optional[
Union[EventHandler, EventSpec, list, function, BaseVar]
] = None,
@ -520,7 +501,7 @@ class HighLevelRadioGroup(RadioGroupRoot):
items: The items of the radio group.
direction: The direction of the radio group.
gap: The gap between the items of the radio group.
size: The size of the radio group: "1" | "2" | "3"
size: The size of the radio group.
variant: The variant of the radio group
color_scheme: The color of the radio group
high_contrast: Whether to render the radio group with higher contrast color against background
@ -529,8 +510,6 @@ class HighLevelRadioGroup(RadioGroupRoot):
disabled: Whether the radio group is disabled
name: The name of the group. Submitted with its owning form as part of a name/value pair.
required: Whether the radio group is required
orientation: The orientation of the component.
loop: When true, keyboard navigation will loop from last item to first, and vice versa.
style: Props to rename The style of the component.
key: A unique key for the component.
id: The id for the component.

View File

@ -7,7 +7,6 @@ from reflex.vars import Var
from ..base import (
LiteralAccentColor,
LiteralRadius,
RadixThemesComponent,
)
@ -32,8 +31,8 @@ class Slider(RadixThemesComponent):
# Whether to render the button with higher contrast color against background
high_contrast: Var[bool]
# Override theme radius for button: "none" | "small" | "medium" | "large" | "full"
radius: Var[LiteralRadius]
# Override theme radius for button: "none" | "small" | "full"
radius: Var[Literal["none", "small", "full"]]
# The value of the slider when initially rendered. Use when you do not need to control the state of the slider.
default_value: Var[Union[List[Union[float, int]], float, int]]

View File

@ -11,7 +11,7 @@ from typing import Any, Dict, List, Literal, Optional, Union
from reflex.components.component import Component
from reflex.constants import EventTriggers
from reflex.vars import Var
from ..base import LiteralAccentColor, LiteralRadius, RadixThemesComponent
from ..base import LiteralAccentColor, RadixThemesComponent
class Slider(RadixThemesComponent):
def get_event_triggers(self) -> Dict[str, Any]: ...
@ -96,8 +96,7 @@ class Slider(RadixThemesComponent):
high_contrast: Optional[Union[Var[bool], bool]] = None,
radius: Optional[
Union[
Var[Literal["none", "small", "medium", "large", "full"]],
Literal["none", "small", "medium", "large", "full"],
Var[Literal["none", "small", "full"]], Literal["none", "small", "full"]
]
] = None,
default_value: Optional[
@ -190,7 +189,7 @@ class Slider(RadixThemesComponent):
variant: Variant of button
color_scheme: Override theme color for button
high_contrast: Whether to render the button with higher contrast color against background
radius: Override theme radius for button: "none" | "small" | "medium" | "large" | "full"
radius: Override theme radius for button: "none" | "small" | "full"
default_value: The value of the slider when initially rendered. Use when you do not need to control the state of the slider.
value: The controlled value of the slider. Must be used in conjunction with onValueChange.
name: The name of the slider. Submitted with its owning form as part of a name/value pair.

View File

@ -6,12 +6,10 @@ from reflex.vars import Var
from ..base import (
LiteralAccentColor,
LiteralRadius,
LiteralVariant,
RadixThemesComponent,
)
LiteralSwitchSize = Literal["1", "2", "3", "4"]
LiteralSwitchSize = Literal["1", "2", "3"]
class Switch(RadixThemesComponent):
@ -43,8 +41,8 @@ class Switch(RadixThemesComponent):
# Switch size "1" - "4"
size: Var[LiteralSwitchSize]
# Variant of switch: "solid" | "soft" | "outline" | "ghost"
variant: Var[LiteralVariant]
# Variant of switch: "classic" | "surface" | "soft"
variant: Var[Literal["classic", "surface", "soft"]]
# Override theme color for switch
color_scheme: Var[LiteralAccentColor]
@ -52,8 +50,8 @@ class Switch(RadixThemesComponent):
# Whether to render the switch with higher contrast color against background
high_contrast: Var[bool]
# Override theme radius for switch: "none" | "small" | "medium" | "large" | "full"
radius: Var[LiteralRadius]
# Override theme radius for switch: "none" | "small" | "full"
radius: Var[Literal["none", "small", "full"]]
# Props to rename
_rename_props = {"onChange": "onCheckedChange"}

View File

@ -10,14 +10,9 @@ from reflex.style import Style
from typing import Any, Dict, Literal
from reflex.constants import EventTriggers
from reflex.vars import Var
from ..base import (
LiteralAccentColor,
LiteralRadius,
LiteralVariant,
RadixThemesComponent,
)
from ..base import LiteralAccentColor, RadixThemesComponent
LiteralSwitchSize = Literal["1", "2", "3", "4"]
LiteralSwitchSize = Literal["1", "2", "3"]
class Switch(RadixThemesComponent):
def get_event_triggers(self) -> Dict[str, Any]: ...
@ -97,19 +92,18 @@ class Switch(RadixThemesComponent):
name: Optional[Union[Var[str], str]] = None,
value: Optional[Union[Var[str], str]] = None,
size: Optional[
Union[Var[Literal["1", "2", "3", "4"]], Literal["1", "2", "3", "4"]]
Union[Var[Literal["1", "2", "3"]], Literal["1", "2", "3"]]
] = None,
variant: Optional[
Union[
Var[Literal["classic", "solid", "soft", "surface", "outline", "ghost"]],
Literal["classic", "solid", "soft", "surface", "outline", "ghost"],
Var[Literal["classic", "surface", "soft"]],
Literal["classic", "surface", "soft"],
]
] = None,
high_contrast: Optional[Union[Var[bool], bool]] = None,
radius: Optional[
Union[
Var[Literal["none", "small", "medium", "large", "full"]],
Literal["none", "small", "medium", "large", "full"],
Var[Literal["none", "small", "full"]], Literal["none", "small", "full"]
]
] = None,
style: Optional[Style] = None,
@ -186,9 +180,9 @@ class Switch(RadixThemesComponent):
name: The name of the switch (when submitting a form)
value: The value associated with the "on" position
size: Switch size "1" - "4"
variant: Variant of switch: "solid" | "soft" | "outline" | "ghost"
variant: Variant of switch: "classic" | "surface" | "soft"
high_contrast: Whether to render the switch with higher contrast color against background
radius: Override theme radius for switch: "none" | "small" | "medium" | "large" | "full"
radius: Override theme radius for switch: "none" | "small" | "full"
style: Props to rename The style of the component.
key: A unique key for the component.
id: The id for the component.

View File

@ -15,9 +15,6 @@ class TabsRoot(RadixThemesComponent):
tag = "Tabs.Root"
# The variant of the tab
variant: Var[Literal["surface", "ghost"]]
# The value of the tab that should be active when initially rendered. Use when you do not need to control the state of the tabs.
default_value: Var[str]
@ -47,6 +44,9 @@ class TabsList(RadixThemesComponent):
tag = "Tabs.List"
# Tabs size "1" - "2"
size: Var[Literal["1", "2"]]
class TabsTrigger(RadixThemesComponent):
"""Trigger an action or event, such as submitting a form or displaying a dialog."""

View File

@ -83,9 +83,6 @@ class TabsRoot(RadixThemesComponent):
],
]
] = None,
variant: Optional[
Union[Var[Literal["surface", "ghost"]], Literal["surface", "ghost"]]
] = None,
default_value: Optional[Union[Var[str], str]] = None,
value: Optional[Union[Var[str], str]] = None,
orientation: Optional[
@ -160,7 +157,6 @@ class TabsRoot(RadixThemesComponent):
*children: Child components.
color: map to CSS default color property.
color_scheme: map to radix color property.
variant: The variant of the tab
default_value: The value of the tab that should be active when initially rendered. Use when you do not need to control the state of the tabs.
value: The controlled value of the tab that should be active. Use when you need to control the state of the tabs.
orientation: The orientation of the tabs.
@ -247,6 +243,7 @@ class TabsList(RadixThemesComponent):
],
]
] = None,
size: Optional[Union[Var[Literal["1", "2"]], Literal["1", "2"]]] = None,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
@ -310,6 +307,7 @@ class TabsList(RadixThemesComponent):
*children: Child components.
color: map to CSS default color property.
color_scheme: map to radix color property.
size: Tabs size "1" - "2"
style: The style of the component.
key: A unique key for the component.
id: The id for the component.

View File

@ -1,5 +1,5 @@
"""Interactive components provided by @radix-ui/themes."""
from typing import Any, Dict, Literal
from typing import Any, Dict, Literal, Union
from reflex import el
from reflex.components.component import Component
@ -29,6 +29,48 @@ class TextArea(RadixThemesComponent, el.Textarea):
# The color of the text area
color_scheme: Var[LiteralAccentColor]
# Whether the form control should have autocomplete enabled
auto_complete: Var[bool]
# Automatically focuses the textarea when the page loads
auto_focus: Var[bool]
# Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted
dirname: Var[str]
# Disables the textarea
disabled: Var[bool]
# Associates the textarea with a form (by id)
form: Var[Union[str, int, bool]]
# Maximum number of characters allowed in the textarea
max_length: Var[int]
# Minimum number of characters required in the textarea
min_length: Var[int]
# Name of the textarea, used when submitting the form
name: Var[str]
# Placeholder text in the textarea
placeholder: Var[str]
# Indicates whether the textarea is read-only
read_only: Var[bool]
# Indicates that the textarea is required
required: Var[bool]
# Visible number of lines in the text control
rows: Var[str]
# The controlled value of the textarea, read only unless used with on_change
value: Var[str]
# How the text in the textarea is to be wrapped when submitting the form
wrap: Var[str]
@classmethod
def create(cls, *children, **props) -> Component:
"""Create an Input component.

View File

@ -7,7 +7,7 @@ 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 typing import Any, Dict, Literal
from typing import Any, Dict, Literal, Union
from reflex import el
from reflex.components.component import Component
from reflex.components.core.debounce import DebounceInput
@ -94,41 +94,21 @@ class TextArea(RadixThemesComponent, el.Textarea):
],
]
] = None,
auto_complete: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
auto_focus: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
cols: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
dirname: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
disabled: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
auto_complete: Optional[Union[Var[bool], bool]] = None,
auto_focus: Optional[Union[Var[bool], bool]] = None,
dirname: Optional[Union[Var[str], str]] = None,
disabled: Optional[Union[Var[bool], bool]] = None,
form: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
max_length: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
min_length: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
name: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
placeholder: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
read_only: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
required: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
rows: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
value: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
wrap: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
max_length: Optional[Union[Var[int], int]] = None,
min_length: Optional[Union[Var[int], int]] = None,
name: Optional[Union[Var[str], str]] = None,
placeholder: Optional[Union[Var[str], str]] = None,
read_only: Optional[Union[Var[bool], bool]] = None,
required: Optional[Union[Var[bool], bool]] = None,
rows: Optional[Union[Var[str], str]] = None,
value: Optional[Union[Var[str], str]] = None,
wrap: Optional[Union[Var[str], str]] = None,
cols: Optional[Union[Var[Union[str, int, bool]], Union[str, int, bool]]] = None,
access_key: Optional[
Union[Var[Union[str, int, bool]], Union[str, int, bool]]
] = None,
@ -244,7 +224,6 @@ class TextArea(RadixThemesComponent, el.Textarea):
color_scheme: The color of the text area
auto_complete: Whether the form control should have autocomplete enabled
auto_focus: Automatically focuses the textarea when the page loads
cols: Visible width of the text control, in average character widths
dirname: Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted
disabled: Disables the textarea
form: Associates the textarea with a form (by id)
@ -257,6 +236,7 @@ class TextArea(RadixThemesComponent, el.Textarea):
rows: Visible number of lines in the text control
value: The controlled value of the textarea, read only unless used with on_change
wrap: How the text in the textarea is to be wrapped when submitting the form
cols: Visible width of the text control, in average character widths
access_key: Provides a hint for generating a keyboard shortcut for the current element.
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
content_editable: Indicates whether the element's content is editable.

View File

@ -14,7 +14,6 @@ from reflex.vars import Var
from ..base import (
LiteralAccentColor,
LiteralRadius,
LiteralSize,
RadixThemesComponent,
)
@ -85,9 +84,6 @@ class TextFieldSlot(RadixThemesComponent):
# Override theme color for text field slot
color_scheme: Var[LiteralAccentColor]
# Override the gap spacing between slot and input: "1" - "9"
gap: Var[LiteralSize]
class Input(RadixThemesComponent):
"""High level wrapper for the Input component."""

View File

@ -16,7 +16,7 @@ from reflex.components.core.debounce import DebounceInput
from reflex.components.lucide.icon import Icon
from reflex.constants import EventTriggers
from reflex.vars import Var
from ..base import LiteralAccentColor, LiteralRadius, LiteralSize, RadixThemesComponent
from ..base import LiteralAccentColor, LiteralRadius, RadixThemesComponent
LiteralTextFieldSize = Literal["1", "2", "3"]
LiteralTextFieldVariant = Literal["classic", "surface", "soft"]
@ -651,12 +651,6 @@ class TextFieldSlot(RadixThemesComponent):
],
]
] = None,
gap: Optional[
Union[
Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],
Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"],
]
] = None,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
@ -720,7 +714,6 @@ class TextFieldSlot(RadixThemesComponent):
*children: Child components.
color: map to CSS default color property.
color_scheme: map to radix color property.
gap: Override the gap spacing between slot and input: "1" - "9"
style: The style of the component.
key: A unique key for the component.
id: The id for the component.

View File

@ -4,6 +4,8 @@ https://www.radix-ui.com/themes/docs/theme/typography
"""
from __future__ import annotations
from typing import Literal
from reflex import el
from reflex.vars import Var
@ -18,6 +20,8 @@ from .base import (
LiteralTextWeight,
)
LiteralType = Literal["p", "label", "div", "span"]
class Text(el.Span, RadixThemesComponent):
"""A foundational text primitive based on the <span> element."""
@ -28,7 +32,7 @@ class Text(el.Span, RadixThemesComponent):
as_child: Var[bool]
# Change the default rendered element into a semantically appropriate alternative (cannot be used with asChild)
as_: Var[str]
as_: Var[LiteralType] = "p" # type: ignore
# Text size: "1" - "9"
size: Var[LiteralTextSize]

View File

@ -7,11 +7,14 @@ 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 typing import Literal
from reflex import el
from reflex.vars import Var
from ..base import LiteralAccentColor, RadixThemesComponent
from .base import LiteralTextAlign, LiteralTextSize, LiteralTextTrim, LiteralTextWeight
LiteralType = Literal["p", "label", "div", "span"]
class Text(el.Span, RadixThemesComponent):
@overload
@classmethod
@ -82,7 +85,12 @@ class Text(el.Span, RadixThemesComponent):
]
] = None,
as_child: Optional[Union[Var[bool], bool]] = None,
as_: Optional[Union[Var[str], str]] = None,
as_: Optional[
Union[
Var[Literal["p", "label", "div", "span"]],
Literal["p", "label", "div", "span"],
]
] = None,
size: Optional[
Union[
Var[Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]],

View File

@ -332,9 +332,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
}
cls.computed_vars = {
v._var_name: v._var_set_state(cls)
for mixin in cls.__mro__
if mixin is cls or not issubclass(mixin, (BaseState, ABC))
for v in mixin.__dict__.values()
for v in cls.__dict__.values()
if isinstance(v, ComputedVar)
}
cls.vars = {
@ -352,10 +350,29 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
events = {
name: fn
for name, fn in cls.__dict__.items()
if not name.startswith("_")
and isinstance(fn, Callable)
and not isinstance(fn, EventHandler)
if cls._item_is_event_handler(name, fn)
}
for mixin in cls._mixins():
for name, value in mixin.__dict__.items():
if isinstance(value, ComputedVar):
fget = cls._copy_fn(value.fget)
newcv = ComputedVar(fget=fget, _var_name=value._var_name)
newcv._var_set_state(cls)
setattr(cls, name, newcv)
cls.computed_vars[newcv._var_name] = newcv
cls.vars[newcv._var_name] = newcv
continue
if events.get(name) is not None:
continue
if not cls._item_is_event_handler(name, value):
continue
if parent_state is not None and parent_state.event_handlers.get(name):
continue
value = cls._copy_fn(value)
value.__qualname__ = f"{cls.__name__}.{name}"
events[name] = value
for name, fn in events.items():
handler = EventHandler(fn=fn)
cls.event_handlers[name] = handler
@ -363,6 +380,58 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
cls._init_var_dependency_dicts()
@staticmethod
def _copy_fn(fn: Callable) -> Callable:
"""Copy a function. Used to copy ComputedVars and EventHandlers from mixins.
Args:
fn: The function to copy.
Returns:
The copied function.
"""
newfn = FunctionType(
fn.__code__,
fn.__globals__,
name=fn.__name__,
argdefs=fn.__defaults__,
closure=fn.__closure__,
)
newfn.__annotations__ = fn.__annotations__
return newfn
@staticmethod
def _item_is_event_handler(name: str, value: Any) -> bool:
"""Check if the item is an event handler.
Args:
name: The name of the item.
value: The value of the item.
Returns:
Whether the item is an event handler.
"""
return (
not name.startswith("_")
and isinstance(value, Callable)
and not isinstance(value, EventHandler)
and hasattr(value, "__code__")
)
@classmethod
def _mixins(cls) -> List[Type]:
"""Get the mixin classes of the state.
Returns:
The mixin classes of the state.
"""
return [
mixin
for mixin in cls.__mro__
if not issubclass(mixin, (BaseState, ABC))
and mixin not in [pydantic.BaseModel, Base]
]
@classmethod
def _init_var_dependency_dicts(cls):
"""Initialize the var dependency tracking dicts.

View File

@ -19,6 +19,7 @@ from typing import (
Set,
Type,
Union,
overload,
_GenericAlias, # type: ignore
)
@ -136,6 +137,16 @@ class ComputedVar(Var):
def _deps(self, objclass: Type, obj: Optional[FunctionType] = ...) -> Set[str]: ...
def mark_dirty(self, instance) -> None: ...
def _determine_var_type(self) -> Type: ...
@overload
def __init__(
self,
fget: Callable[[BaseState], Any],
fset: Callable[[BaseState, Any], None] | None = None,
fdel: Callable[[BaseState], Any] | None = None,
doc: str | None = None,
**kwargs,
) -> None: ...
@overload
def __init__(self, func) -> None: ...
def cached_var(fget: Callable[[Any], Any]) -> ComputedVar: ...