Merge branch 'main' into lendemor/fix_duplicate_tab_issue

This commit is contained in:
Lendemor 2025-02-20 15:12:04 +01:00
commit d2b183e3f9
366 changed files with 55599 additions and 17272 deletions

2
.github/codeql-config.yml vendored Normal file
View File

@ -0,0 +1,2 @@
paths-ignore:
- "**/tests/**"

View File

@ -70,58 +70,6 @@ jobs:
env: env:
GITHUB_SHA: ${{ github.sha }} GITHUB_SHA: ${{ github.sha }}
simple-apps-benchmarks: # This app tests the compile times of various compoonents and pages
if: github.event.pull_request.merged == true
env:
OUTPUT_FILE: benchmarks.json
timeout-minutes: 50
strategy:
# Prioritize getting more information out of the workflow (even if something fails)
fail-fast: false
matrix:
# Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.9.21", "3.10.16", "3.11.11", "3.12.8"]
exclude:
- os: windows-latest
python-version: "3.10.16"
- os: windows-latest
python-version: "3.9.21"
# keep only one python version for MacOS
- os: macos-latest
python-version: "3.9.21"
- os: macos-latest
python-version: "3.10.16"
- os: macos-latest
python-version: "3.11.11"
include:
- os: windows-latest
python-version: "3.10.11"
- os: windows-latest
python-version: "3.9.13"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- name: Run benchmark tests
env:
APP_HARNESS_HEADLESS: 1
PYTHONUNBUFFERED: 1
run: |
poetry run pytest -v benchmarks/ --benchmark-json=${{ env.OUTPUT_FILE }} -s
- name: Upload benchmark results
# Only run if the database creds are available in this context.
run:
poetry run python benchmarks/benchmark_compile_times.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--benchmark-json "${{ env.OUTPUT_FILE }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--event-type "${{ github.event_name }}" --pr-id "${{ github.event.pull_request.id }}"
reflex-dist-size: # This job is used to calculate the size of the Reflex distribution (wheel file) reflex-dist-size: # This job is used to calculate the size of the Reflex distribution (wheel file)
if: github.event.pull_request.merged == true if: github.event.pull_request.merged == true
timeout-minutes: 30 timeout-minutes: 30
@ -161,7 +109,11 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up python
id: setup-python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry - name: Install Poetry
uses: snok/install-poetry@v1 uses: snok/install-poetry@v1
with: with:

View File

@ -16,7 +16,7 @@ jobs:
- uses: ./.github/actions/setup_build_env - uses: ./.github/actions/setup_build_env
with: with:
python-version: "3.9.21" python-version: '3.10'
run-poetry-install: true run-poetry-install: true
create-venv-at-path: .venv create-venv-at-path: .venv
@ -55,7 +55,7 @@ jobs:
path: reflex-web path: reflex-web
- name: Install Requirements for reflex-web - name: Install Requirements for reflex-web
working-directory: ./reflex-web working-directory: ./reflex-web
run: poetry run uv pip install -r requirements.txt run: poetry run uv pip install $(grep -ivE "reflex " requirements.txt)
- name: Install additional dependencies for DB access - name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg run: poetry run uv pip install psycopg
- name: Init Website for reflex-web - name: Init Website for reflex-web
@ -73,7 +73,7 @@ jobs:
echo "$outdated" echo "$outdated"
# Ignore 3rd party dependencies that are not updated. # Ignore 3rd party dependencies that are not updated.
filtered_outdated=$(echo "$outdated" | grep -vE 'Package|@chakra-ui|lucide-react|@splinetool/runtime|ag-grid-react|framer-motion|react-markdown|remark-math|remark-gfm|rehype-katex|rehype-raw|remark-unwrap-images' || true) filtered_outdated=$(echo "$outdated" | grep -vE 'Package|@chakra-ui|lucide-react|@splinetool/runtime|ag-grid-react|framer-motion|react-markdown|remark-math|remark-gfm|rehype-katex|rehype-raw|remark-unwrap-images|ag-grid' || true)
no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true) no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true)

103
.github/workflows/codeql.yml vendored Normal file
View File

@ -0,0 +1,103 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Advanced"
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
schedule:
- cron: "36 7 * * 4"
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: javascript-typescript
build-mode: none
- language: python
build-mode: none
- language: actions
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
# - name: Setup runtime (example)
# uses: actions/setup-example@v1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
config-file: .github/codeql-config.yml
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View File

@ -47,17 +47,10 @@ jobs:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
run-poetry-install: true run-poetry-install: true
create-venv-at-path: .venv create-venv-at-path: .venv
- run: poetry run uv pip install pyvirtualdisplay pillow pytest-split - run: poetry run uv pip install pyvirtualdisplay pillow pytest-split pytest-retry
- name: Run app harness tests - name: Run app harness tests
env: env:
SCREENSHOT_DIR: /tmp/screenshots/${{ matrix.state_manager }}/${{ matrix.python-version }}/${{ matrix.split_index }}
REDIS_URL: ${{ matrix.state_manager == 'redis' && 'redis://localhost:6379' || '' }} REDIS_URL: ${{ matrix.state_manager == 'redis' && 'redis://localhost:6379' || '' }}
run: | run: |
poetry run playwright install chromium poetry run playwright install chromium
poetry run pytest tests/integration --splits 2 --group ${{matrix.split_index}} poetry run pytest tests/integration --retries 3 --maxfail=5 --splits 2 --group ${{matrix.split_index}}
- uses: actions/upload-artifact@v4
name: Upload failed test screenshots
if: always()
with:
name: failed_test_screenshots
path: /tmp/screenshots

View File

@ -33,7 +33,7 @@ env:
PR_TITLE: ${{ github.event.pull_request.title }} PR_TITLE: ${{ github.event.pull_request.title }}
jobs: jobs:
example-counter: example-counter-and-nba-proxy:
env: env:
OUTPUT_FILE: import_benchmark.json OUTPUT_FILE: import_benchmark.json
timeout-minutes: 30 timeout-minutes: 30
@ -43,22 +43,17 @@ jobs:
matrix: matrix:
# Show OS combos first in GUI # Show OS combos first in GUI
os: [ubuntu-latest, windows-latest] os: [ubuntu-latest, windows-latest]
python-version: ["3.9.21", "3.10.16", "3.11.11", "3.12.8", "3.13.1"] python-version: ['3.10.16', '3.11.11', '3.12.8', '3.13.1']
# Windows is a bit behind on Python version availability in Github
exclude: exclude:
- os: windows-latest - os: windows-latest
python-version: "3.11.11" python-version: "3.11.11"
- os: windows-latest - os: windows-latest
python-version: "3.10.16" python-version: '3.10.16'
- os: windows-latest
python-version: "3.9.21"
include: include:
- os: windows-latest - os: windows-latest
python-version: "3.11.9" python-version: "3.11.9"
- os: windows-latest - os: windows-latest
python-version: "3.10.11" python-version: '3.10.11'
- os: windows-latest
python-version: "3.9.13"
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
@ -84,8 +79,6 @@ jobs:
run: | run: |
poetry run reflex export --backend-only poetry run reflex export --backend-only
- name: Check run --backend-only before init for counter example - name: Check run --backend-only before init for counter example
env:
WAIT_FOR_LISTENING_PORT_ARGS: --path ping
run: | run: |
poetry run bash scripts/integration.sh ./reflex-examples/counter dev 8001 --backend-only --backend-port 8001 poetry run bash scripts/integration.sh ./reflex-examples/counter dev 8001 --backend-only --backend-port 8001
- name: Init Website for counter example - name: Init Website for counter example
@ -101,26 +94,26 @@ jobs:
# Check that npm is home # Check that npm is home
npm -v npm -v
poetry run bash scripts/integration.sh ./reflex-examples/counter dev poetry run bash scripts/integration.sh ./reflex-examples/counter dev
- name: Measure and upload .web size - name: Install requirements for nba proxy example
run: working-directory: ./reflex-examples/nba-proxy
poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}" run: |
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}" poetry run uv pip install -r requirements.txt
--pr-id "${{ github.event.pull_request.id }}" - name: Install additional dependencies for DB access
--branch-name "${{ github.head_ref || github.ref_name }}" run: poetry run uv pip install psycopg
--path ./reflex-examples/counter/.web - name: Check export --backend-only before init for nba-proxy example
--app-name "counter" working-directory: ./reflex-examples/nba-proxy
- name: Install hyperfine run: |
run: cargo install hyperfine poetry run reflex export --backend-only
- name: Benchmark imports - name: Init Website for nba-proxy example
working-directory: ./reflex-examples/counter working-directory: ./reflex-examples/nba-proxy
run: hyperfine --warmup 3 "export POETRY_VIRTUALENVS_PATH=../../.venv; poetry run python counter/counter.py" --show-output --export-json "${{ env.OUTPUT_FILE }}" --shell bash run: |
- name: Upload Benchmarks poetry run reflex init --loglevel debug
run: - name: Run Website and Check for errors
poetry run python benchmarks/benchmark_imports.py --os "${{ matrix.os }}" run: |
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}" # Check that npm is home
--benchmark-json "./reflex-examples/counter/${{ env.OUTPUT_FILE }}" npm -v
--branch-name "${{ github.head_ref || github.ref_name }}" --pr-id "${{ github.event.pull_request.id }}" poetry run bash scripts/integration.sh ./reflex-examples/nba-proxy dev
--app-name "counter"
reflex-web: reflex-web:
strategy: strategy:
@ -161,12 +154,6 @@ jobs:
# Check that npm is home # Check that npm is home
npm -v npm -v
poetry run bash scripts/integration.sh ./reflex-web prod poetry run bash scripts/integration.sh ./reflex-web prod
- name: Measure and upload .web size
run:
poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--pr-id "${{ github.event.pull_request.id }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--app-name "reflex-web" --path ./reflex-web/.web
rx-shout-from-template: rx-shout-from-template:
strategy: strategy:
@ -230,9 +217,3 @@ jobs:
# Check that npm is home # Check that npm is home
npm -v npm -v
poetry run bash scripts/integration.sh ./reflex-web prod poetry run bash scripts/integration.sh ./reflex-web prod
- name: Measure and upload .web size
run:
poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--pr-id "${{ github.event.pull_request.id }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--app-name "reflex-web" --path ./reflex-web/.web

View File

@ -78,7 +78,6 @@ jobs:
shell: wsl-bash {0} shell: wsl-bash {0}
run: | run: |
export TELEMETRY_ENABLED=false export TELEMETRY_ENABLED=false
export WAIT_FOR_LISTENING_PORT_ARGS="--path ping"
dos2unix scripts/integration.sh dos2unix scripts/integration.sh
poetry run bash scripts/integration.sh ./reflex-examples/counter dev 8001 --backend-only --backend-port 8001 poetry run bash scripts/integration.sh ./reflex-examples/counter dev 8001 --backend-only --backend-port 8001
- name: Init Website for counter example - name: Init Website for counter example

34
.github/workflows/performance.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: performance-tests
on:
push:
branches:
- "main" # or "master"
paths-ignore:
- "**/*.md"
pull_request:
workflow_dispatch:
env:
TELEMETRY_ENABLED: false
NODE_OPTIONS: "--max_old_space_size=8192"
PR_TITLE: ${{ github.event.pull_request.title }}
APP_HARNESS_HEADLESS: 1
PYTHONUNBUFFERED: 1
jobs:
benchmarks:
name: Run benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: 3.12.8
run-poetry-install: true
create-venv-at-path: .venv
- name: Run benchmarks
uses: CodSpeedHQ/action@v3
with:
token: ${{ secrets.CODSPEED_TOKEN }}
run: poetry run pytest tests/benchmarks --codspeed

View File

@ -28,22 +28,18 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest] os: [ubuntu-latest, windows-latest]
python-version: ["3.9.21", "3.10.16", "3.11.11", "3.12.8", "3.13.1"] python-version: ["3.10.16", "3.11.11", "3.12.8", "3.13.1"]
# Windows is a bit behind on Python version availability in Github # Windows is a bit behind on Python version availability in Github
exclude: exclude:
- os: windows-latest - os: windows-latest
python-version: "3.11.11" python-version: "3.11.11"
- os: windows-latest - os: windows-latest
python-version: "3.10.16" python-version: "3.10.16"
- os: windows-latest
python-version: "3.9.21"
include: include:
- os: windows-latest - os: windows-latest
python-version: "3.11.9" python-version: "3.11.9"
- os: windows-latest - os: windows-latest
python-version: "3.10.11" python-version: "3.10.11"
- os: windows-latest
python-version: "3.9.13"
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
# Service containers to run with `runner-job` # Service containers to run with `runner-job`
@ -92,8 +88,8 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
# Note: py39, py310, py311 versions chosen due to available arm64 darwin builds. # Note: py310, py311 versions chosen due to available arm64 darwin builds.
python-version: ["3.9.13", "3.10.11", "3.11.9", "3.12.8", "3.13.1"] python-version: ["3.10.11", "3.11.9", "3.12.8", "3.13.1"]
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

2
.gitignore vendored
View File

@ -4,6 +4,7 @@ assets/external/*
dist/* dist/*
examples/ examples/
.web .web
.states
.idea .idea
.vscode .vscode
.coverage .coverage
@ -14,3 +15,4 @@ requirements.txt
.pyi_generator_last_run .pyi_generator_last_run
.pyi_generator_diff .pyi_generator_diff
reflex.db reflex.db
.codspeed

View File

@ -3,7 +3,7 @@ fail_fast: true
repos: repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit - repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.8.2 rev: v0.9.6
hooks: hooks:
- id: ruff-format - id: ruff-format
args: [reflex, tests] args: [reflex, tests]
@ -24,11 +24,12 @@ repos:
name: update-pyi-files name: update-pyi-files
always_run: true always_run: true
language: system language: system
require_serial: true
description: 'Update pyi files as needed' description: 'Update pyi files as needed'
entry: python3 scripts/make_pyi.py entry: python3 scripts/make_pyi.py
- repo: https://github.com/RobertCraigie/pyright-python - repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.313 rev: v1.1.393
hooks: hooks:
- id: pyright - id: pyright
args: [reflex, tests] args: [reflex, tests]

View File

@ -8,7 +8,7 @@ Here is a quick guide on how to run Reflex repo locally so you can start contrib
**Prerequisites:** **Prerequisites:**
- Python >= 3.9 - Python >= 3.10
- Poetry version >= 1.4.0 and add it to your path (see [Poetry Docs](https://python-poetry.org/docs/#installation) for more info). - Poetry version >= 1.4.0 and add it to your path (see [Poetry Docs](https://python-poetry.org/docs/#installation) for more info).
**1. Fork this repository:** **1. Fork this repository:**
@ -87,7 +87,7 @@ poetry run ruff format .
``` ```
Consider installing git pre-commit hooks so Ruff, Pyright, Darglint and `make_pyi` will run automatically before each commit. Consider installing git pre-commit hooks so Ruff, Pyright, Darglint and `make_pyi` will run automatically before each commit.
Note that pre-commit will only be installed when you use a Python version >= 3.9. Note that pre-commit will only be installed when you use a Python version >= 3.10.
``` bash ``` bash
pre-commit install pre-commit install

View File

@ -34,7 +34,7 @@ See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architectu
## ⚙️ Installation ## ⚙️ Installation
Open a terminal and run (Requires Python 3.9+): Open a terminal and run (Requires Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -21,7 +21,7 @@ def get_package_size(venv_path: Path, os_name):
ValueError: when venv does not exist or python version is None. ValueError: when venv does not exist or python version is None.
""" """
python_version = get_python_version(venv_path, os_name) python_version = get_python_version(venv_path, os_name)
print("Python version:", python_version) # noqa: T201 print("Python version:", python_version)
if python_version is None: if python_version is None:
raise ValueError("Error: Failed to determine Python version.") raise ValueError("Error: Failed to determine Python version.")

View File

@ -1,376 +0,0 @@
"""Benchmark tests for apps with varying component numbers."""
from __future__ import annotations
import functools
import time
from typing import Generator
import pytest
from benchmarks import WINDOWS_SKIP_REASON
from reflex import constants
from reflex.compiler import utils
from reflex.testing import AppHarness, chdir
from reflex.utils import build
from reflex.utils.prerequisites import get_web_dir
web_pages = get_web_dir() / constants.Dirs.PAGES
def render_component(num: int):
"""Generate a number of components based on num.
Args:
num: number of components to produce.
Returns:
The rendered number of components.
"""
import reflex as rx
return [
rx.fragment(
rx.box(
rx.accordion.root(
rx.accordion.item(
header="Full Ingredients", # type: ignore
content="Yes. It's built with accessibility in mind.", # type: ignore
font_size="3em",
),
rx.accordion.item(
header="Applications", # type: ignore
content="Yes. It's unstyled by default, giving you freedom over the look and feel.", # type: ignore
),
collapsible=True,
variant="ghost",
width="25rem",
),
padding_top="20px",
),
rx.box(
rx.drawer.root(
rx.drawer.trigger(
rx.button("Open Drawer with snap points"), as_child=True
),
rx.drawer.overlay(),
rx.drawer.portal(
rx.drawer.content(
rx.flex(
rx.drawer.title("Drawer Content"),
rx.drawer.description("Drawer description"),
rx.drawer.close(
rx.button("Close Button"),
as_child=True,
),
direction="column",
margin="5em",
align_items="center",
),
top="auto",
height="100%",
flex_direction="column",
background_color="var(--green-3)",
),
),
snap_points=["148px", "355px", 1],
),
),
rx.box(
rx.callout(
"You will need admin privileges to install and access this application.",
icon="info",
size="3",
),
),
rx.box(
rx.table.root(
rx.table.header(
rx.table.row(
rx.table.column_header_cell("Full name"),
rx.table.column_header_cell("Email"),
rx.table.column_header_cell("Group"),
),
),
rx.table.body(
rx.table.row(
rx.table.row_header_cell("Danilo Sousa"),
rx.table.cell("danilo@example.com"),
rx.table.cell("Developer"),
),
rx.table.row(
rx.table.row_header_cell("Zahra Ambessa"),
rx.table.cell("zahra@example.com"),
rx.table.cell("Admin"),
),
rx.table.row(
rx.table.row_header_cell("Jasper Eriksson"),
rx.table.cell("jasper@example.com"),
rx.table.cell("Developer"),
),
),
)
),
)
] * num
def AppWithTenComponentsOnePage():
"""A reflex app with roughly 10 components on one page."""
import reflex as rx
def index() -> rx.Component:
return rx.center(rx.vstack(*render_component(1)))
app = rx.App(state=rx.State)
app.add_page(index)
def AppWithHundredComponentOnePage():
"""A reflex app with roughly 100 components on one page."""
import reflex as rx
def index() -> rx.Component:
return rx.center(rx.vstack(*render_component(100)))
app = rx.App(state=rx.State)
app.add_page(index)
def AppWithThousandComponentsOnePage():
"""A reflex app with roughly 1000 components on one page."""
import reflex as rx
def index() -> rx.Component:
return rx.center(rx.vstack(*render_component(1000)))
app = rx.App(state=rx.State)
app.add_page(index)
@pytest.fixture(scope="session")
def app_with_10_components(
tmp_path_factory,
) -> Generator[AppHarness, None, None]:
"""Start Blank Template app at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
running AppHarness instance
"""
root = tmp_path_factory.mktemp("app10components")
yield AppHarness.create(
root=root,
app_source=functools.partial(
AppWithTenComponentsOnePage,
render_component=render_component, # type: ignore
),
) # type: ignore
@pytest.fixture(scope="session")
def app_with_100_components(
tmp_path_factory,
) -> Generator[AppHarness, None, None]:
"""Start Blank Template app at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
running AppHarness instance
"""
root = tmp_path_factory.mktemp("app100components")
yield AppHarness.create(
root=root,
app_source=functools.partial(
AppWithHundredComponentOnePage,
render_component=render_component, # type: ignore
),
) # type: ignore
@pytest.fixture(scope="session")
def app_with_1000_components(
tmp_path_factory,
) -> Generator[AppHarness, None, None]:
"""Create an app with 1000 components at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
an AppHarness instance
"""
root = tmp_path_factory.mktemp("app1000components")
yield AppHarness.create(
root=root,
app_source=functools.partial(
AppWithThousandComponentsOnePage,
render_component=render_component, # type: ignore
),
) # type: ignore
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
@pytest.mark.benchmark(
group="Compile time of varying component numbers",
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_10_compile_time_cold(benchmark, app_with_10_components):
"""Test the compile time on a cold start for an app with roughly 10 components.
Args:
benchmark: The benchmark fixture.
app_with_10_components: The app harness.
"""
def setup():
with chdir(app_with_10_components.app_path):
utils.empty_dir(web_pages, ["_app.js"])
app_with_10_components._initialize_app()
build.setup_frontend(app_with_10_components.app_path)
def benchmark_fn():
with chdir(app_with_10_components.app_path):
app_with_10_components.app_instance._compile()
benchmark.pedantic(benchmark_fn, setup=setup, rounds=10)
@pytest.mark.benchmark(
group="Compile time of varying component numbers",
min_rounds=5,
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_10_compile_time_warm(benchmark, app_with_10_components):
"""Test the compile time on a warm start for an app with roughly 10 components.
Args:
benchmark: The benchmark fixture.
app_with_10_components: The app harness.
"""
with chdir(app_with_10_components.app_path):
app_with_10_components._initialize_app()
build.setup_frontend(app_with_10_components.app_path)
def benchmark_fn():
with chdir(app_with_10_components.app_path):
app_with_10_components.app_instance._compile()
benchmark(benchmark_fn)
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
@pytest.mark.benchmark(
group="Compile time of varying component numbers",
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_100_compile_time_cold(benchmark, app_with_100_components):
"""Test the compile time on a cold start for an app with roughly 100 components.
Args:
benchmark: The benchmark fixture.
app_with_100_components: The app harness.
"""
def setup():
with chdir(app_with_100_components.app_path):
utils.empty_dir(web_pages, ["_app.js"])
app_with_100_components._initialize_app()
build.setup_frontend(app_with_100_components.app_path)
def benchmark_fn():
with chdir(app_with_100_components.app_path):
app_with_100_components.app_instance._compile()
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
@pytest.mark.benchmark(
group="Compile time of varying component numbers",
min_rounds=5,
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_100_compile_time_warm(benchmark, app_with_100_components):
"""Test the compile time on a warm start for an app with roughly 100 components.
Args:
benchmark: The benchmark fixture.
app_with_100_components: The app harness.
"""
with chdir(app_with_100_components.app_path):
app_with_100_components._initialize_app()
build.setup_frontend(app_with_100_components.app_path)
def benchmark_fn():
with chdir(app_with_100_components.app_path):
app_with_100_components.app_instance._compile()
benchmark(benchmark_fn)
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
@pytest.mark.benchmark(
group="Compile time of varying component numbers",
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_1000_compile_time_cold(benchmark, app_with_1000_components):
"""Test the compile time on a cold start for an app with roughly 1000 components.
Args:
benchmark: The benchmark fixture.
app_with_1000_components: The app harness.
"""
def setup():
with chdir(app_with_1000_components.app_path):
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_1000_components._initialize_app()
build.setup_frontend(app_with_1000_components.app_path)
def benchmark_fn():
with chdir(app_with_1000_components.app_path):
app_with_1000_components.app_instance._compile()
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
@pytest.mark.benchmark(
group="Compile time of varying component numbers",
min_rounds=5,
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_1000_compile_time_warm(benchmark, app_with_1000_components):
"""Test the compile time on a warm start for an app with roughly 1000 components.
Args:
benchmark: The benchmark fixture.
app_with_1000_components: The app harness.
"""
with chdir(app_with_1000_components.app_path):
app_with_1000_components._initialize_app()
build.setup_frontend(app_with_1000_components.app_path)
def benchmark_fn():
with chdir(app_with_1000_components.app_path):
app_with_1000_components.app_instance._compile()
benchmark(benchmark_fn)

View File

@ -1,579 +0,0 @@
"""Benchmark tests for apps with varying page numbers."""
from __future__ import annotations
import functools
import time
from typing import Generator
import pytest
from benchmarks import WINDOWS_SKIP_REASON
from reflex import constants
from reflex.compiler import utils
from reflex.testing import AppHarness, chdir
from reflex.utils import build
from reflex.utils.prerequisites import get_web_dir
web_pages = get_web_dir() / constants.Dirs.PAGES
def render_multiple_pages(app, num: int):
"""Add multiple pages based on num.
Args:
app: The App object.
num: number of pages to render.
"""
from typing import Tuple
from rxconfig import config # type: ignore
import reflex as rx
docs_url = "https://reflex.dev/docs/getting-started/introduction/"
filename = f"{config.app_name}/{config.app_name}.py"
college = [
"Stanford University",
"Arizona",
"Arizona state",
"Baylor",
"Boston College",
"Boston University",
]
class State(rx.State):
"""The app state."""
position: str
college: str
age: Tuple[int, int] = (18, 50)
salary: Tuple[int, int] = (0, 25000000)
comp1 = rx.center(
rx.theme_panel(),
rx.vstack(
rx.heading("Welcome to Reflex!", size="9"),
rx.text("Get started by editing ", rx.code(filename)),
rx.button(
"Check out our docs!",
on_click=lambda: rx.redirect(docs_url),
size="4",
),
align="center",
spacing="7",
font_size="2em",
),
height="100vh",
)
comp2 = rx.vstack(
rx.hstack(
rx.vstack(
rx.select(
["C", "PF", "SF", "PG", "SG"],
placeholder="Select a position. (All)",
on_change=State.set_position, # type: ignore
size="3",
),
rx.select(
college,
placeholder="Select a college. (All)",
on_change=State.set_college, # type: ignore
size="3",
),
),
rx.vstack(
rx.vstack(
rx.hstack(
rx.badge("Min Age: ", State.age[0]),
rx.divider(orientation="vertical"),
rx.badge("Max Age: ", State.age[1]),
),
rx.slider(
default_value=[18, 50],
min=18,
max=50,
on_value_commit=State.set_age, # type: ignore
),
align_items="left",
width="100%",
),
rx.vstack(
rx.hstack(
rx.badge("Min Sal: ", State.salary[0] // 1000000, "M"),
rx.divider(orientation="vertical"),
rx.badge("Max Sal: ", State.salary[1] // 1000000, "M"),
),
rx.slider(
default_value=[0, 25000000],
min=0,
max=25000000,
on_value_commit=State.set_salary, # type: ignore
),
align_items="left",
width="100%",
),
),
spacing="4",
),
width="100%",
)
for i in range(1, num + 1):
if i % 2 == 1:
app.add_page(comp1, route=f"page{i}")
else:
app.add_page(comp2, route=f"page{i}")
def AppWithOnePage():
"""A reflex app with one page."""
from rxconfig import config # type: ignore
import reflex as rx
docs_url = "https://reflex.dev/docs/getting-started/introduction/"
filename = f"{config.app_name}/{config.app_name}.py"
class State(rx.State):
"""The app state."""
pass
def index() -> rx.Component:
return rx.center(
rx.input(
id="token", value=State.router.session.client_token, is_read_only=True
),
rx.vstack(
rx.heading("Welcome to Reflex!", size="9"),
rx.text("Get started by editing ", rx.code(filename)),
rx.button(
"Check out our docs!",
on_click=lambda: rx.redirect(docs_url),
size="4",
),
align="center",
spacing="7",
font_size="2em",
),
height="100vh",
)
app = rx.App(state=rx.State)
app.add_page(index)
def AppWithTenPages():
"""A reflex app with 10 pages."""
import reflex as rx
app = rx.App(state=rx.State)
render_multiple_pages(app, 10)
def AppWithHundredPages():
"""A reflex app with 100 pages."""
import reflex as rx
app = rx.App(state=rx.State)
render_multiple_pages(app, 100)
def AppWithThousandPages():
"""A reflex app with Thousand pages."""
import reflex as rx
app = rx.App(state=rx.State)
render_multiple_pages(app, 1000)
def AppWithTenThousandPages():
"""A reflex app with ten thousand pages."""
import reflex as rx
app = rx.App(state=rx.State)
render_multiple_pages(app, 10000)
@pytest.fixture(scope="session")
def app_with_one_page(
tmp_path_factory,
) -> Generator[AppHarness, None, None]:
"""Create an app with 10000 pages at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
an AppHarness instance
"""
root = tmp_path_factory.mktemp("app1")
yield AppHarness.create(root=root, app_source=AppWithOnePage)
@pytest.fixture(scope="session")
def app_with_ten_pages(
tmp_path_factory,
) -> Generator[AppHarness, None, None]:
"""Create an app with 10 pages at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
an AppHarness instance
"""
root = tmp_path_factory.mktemp("app10")
yield AppHarness.create(
root=root,
app_source=functools.partial(
AppWithTenPages,
render_comp=render_multiple_pages, # type: ignore
),
)
@pytest.fixture(scope="session")
def app_with_hundred_pages(
tmp_path_factory,
) -> Generator[AppHarness, None, None]:
"""Create an app with 100 pages at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
an AppHarness instance
"""
root = tmp_path_factory.mktemp("app100")
yield AppHarness.create(
root=root,
app_source=functools.partial(
AppWithHundredPages,
render_comp=render_multiple_pages, # type: ignore
),
) # type: ignore
@pytest.fixture(scope="session")
def app_with_thousand_pages(
tmp_path_factory,
) -> Generator[AppHarness, None, None]:
"""Create an app with 1000 pages at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
an AppHarness instance
"""
root = tmp_path_factory.mktemp("app1000")
yield AppHarness.create(
root=root,
app_source=functools.partial(
AppWithThousandPages,
render_comp=render_multiple_pages, # type: ignore
),
) # type: ignore
@pytest.fixture(scope="session")
def app_with_ten_thousand_pages(
tmp_path_factory,
) -> Generator[AppHarness, None, None]:
"""Create an app with 10000 pages at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
running AppHarness instance
"""
root = tmp_path_factory.mktemp("app10000")
yield AppHarness.create(
root=root,
app_source=functools.partial(
AppWithTenThousandPages,
render_comp=render_multiple_pages, # type: ignore
),
) # type: ignore
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_1_compile_time_cold(benchmark, app_with_one_page):
"""Test the compile time on a cold start for an app with 1 page.
Args:
benchmark: The benchmark fixture.
app_with_one_page: The app harness.
"""
def setup():
with chdir(app_with_one_page.app_path):
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_one_page._initialize_app()
build.setup_frontend(app_with_one_page.app_path)
def benchmark_fn():
with chdir(app_with_one_page.app_path):
app_with_one_page.app_instance._compile()
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
app_with_one_page._reload_state_module()
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
min_rounds=5,
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_1_compile_time_warm(benchmark, app_with_one_page):
"""Test the compile time on a warm start for an app with 1 page.
Args:
benchmark: The benchmark fixture.
app_with_one_page: The app harness.
"""
with chdir(app_with_one_page.app_path):
app_with_one_page._initialize_app()
build.setup_frontend(app_with_one_page.app_path)
def benchmark_fn():
with chdir(app_with_one_page.app_path):
app_with_one_page.app_instance._compile()
benchmark(benchmark_fn)
app_with_one_page._reload_state_module()
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_10_compile_time_cold(benchmark, app_with_ten_pages):
"""Test the compile time on a cold start for an app with 10 page.
Args:
benchmark: The benchmark fixture.
app_with_ten_pages: The app harness.
"""
def setup():
with chdir(app_with_ten_pages.app_path):
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_ten_pages._initialize_app()
build.setup_frontend(app_with_ten_pages.app_path)
def benchmark_fn():
with chdir(app_with_ten_pages.app_path):
app_with_ten_pages.app_instance._compile()
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
app_with_ten_pages._reload_state_module()
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
min_rounds=5,
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_10_compile_time_warm(benchmark, app_with_ten_pages):
"""Test the compile time on a warm start for an app with 10 page.
Args:
benchmark: The benchmark fixture.
app_with_ten_pages: The app harness.
"""
with chdir(app_with_ten_pages.app_path):
app_with_ten_pages._initialize_app()
build.setup_frontend(app_with_ten_pages.app_path)
def benchmark_fn():
with chdir(app_with_ten_pages.app_path):
app_with_ten_pages.app_instance._compile()
benchmark(benchmark_fn)
app_with_ten_pages._reload_state_module()
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_100_compile_time_cold(benchmark, app_with_hundred_pages):
"""Test the compile time on a cold start for an app with 100 page.
Args:
benchmark: The benchmark fixture.
app_with_hundred_pages: The app harness.
"""
def setup():
with chdir(app_with_hundred_pages.app_path):
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_hundred_pages._initialize_app()
build.setup_frontend(app_with_hundred_pages.app_path)
def benchmark_fn():
with chdir(app_with_hundred_pages.app_path):
app_with_hundred_pages.app_instance._compile()
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
app_with_hundred_pages._reload_state_module()
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
min_rounds=5,
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_100_compile_time_warm(benchmark, app_with_hundred_pages):
"""Test the compile time on a warm start for an app with 100 page.
Args:
benchmark: The benchmark fixture.
app_with_hundred_pages: The app harness.
"""
with chdir(app_with_hundred_pages.app_path):
app_with_hundred_pages._initialize_app()
build.setup_frontend(app_with_hundred_pages.app_path)
def benchmark_fn():
with chdir(app_with_hundred_pages.app_path):
app_with_hundred_pages.app_instance._compile()
benchmark(benchmark_fn)
app_with_hundred_pages._reload_state_module()
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_1000_compile_time_cold(benchmark, app_with_thousand_pages):
"""Test the compile time on a cold start for an app with 1000 page.
Args:
benchmark: The benchmark fixture.
app_with_thousand_pages: The app harness.
"""
def setup():
with chdir(app_with_thousand_pages.app_path):
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_thousand_pages._initialize_app()
build.setup_frontend(app_with_thousand_pages.app_path)
def benchmark_fn():
with chdir(app_with_thousand_pages.app_path):
app_with_thousand_pages.app_instance._compile()
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
app_with_thousand_pages._reload_state_module()
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
min_rounds=5,
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_1000_compile_time_warm(benchmark, app_with_thousand_pages):
"""Test the compile time on a warm start for an app with 1000 page.
Args:
benchmark: The benchmark fixture.
app_with_thousand_pages: The app harness.
"""
with chdir(app_with_thousand_pages.app_path):
app_with_thousand_pages._initialize_app()
build.setup_frontend(app_with_thousand_pages.app_path)
def benchmark_fn():
with chdir(app_with_thousand_pages.app_path):
app_with_thousand_pages.app_instance._compile()
benchmark(benchmark_fn)
app_with_thousand_pages._reload_state_module()
@pytest.mark.skip
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_10000_compile_time_cold(benchmark, app_with_ten_thousand_pages):
"""Test the compile time on a cold start for an app with 10000 page.
Args:
benchmark: The benchmark fixture.
app_with_ten_thousand_pages: The app harness.
"""
def setup():
with chdir(app_with_ten_thousand_pages.app_path):
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_ten_thousand_pages._initialize_app()
build.setup_frontend(app_with_ten_thousand_pages.app_path)
def benchmark_fn():
with chdir(app_with_ten_thousand_pages.app_path):
app_with_ten_thousand_pages.app_instance._compile()
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
app_with_ten_thousand_pages._reload_state_module()
@pytest.mark.skip
@pytest.mark.benchmark(
group="Compile time of varying page numbers",
min_rounds=5,
timer=time.perf_counter,
disable_gc=True,
warmup=False,
)
def test_app_10000_compile_time_warm(benchmark, app_with_ten_thousand_pages):
"""Test the compile time on a warm start for an app with 10000 page.
Args:
benchmark: The benchmark fixture.
app_with_ten_thousand_pages: The app harness.
"""
def benchmark_fn():
with chdir(app_with_ten_thousand_pages.app_path):
app_with_ten_thousand_pages.app_instance._compile()
benchmark(benchmark_fn)
app_with_ten_thousand_pages._reload_state_module()

View File

@ -34,7 +34,7 @@ Auf unserer [Architektur-Seite](https://reflex.dev/blog/2024-03-21-reflex-archit
## ⚙️ Installation ## ⚙️ Installation
Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.9+): Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -35,7 +35,7 @@ Consulta nuestra [página de arquitectura](https://reflex.dev/blog/2024-03-21-re
## ⚙️ Instalación ## ⚙️ Instalación
Abra un terminal y ejecute (Requiere Python 3.9+): Abra un terminal y ejecute (Requiere Python 3.10+):
```bash ```bash
pip install reflex pip install reflex
@ -239,7 +239,7 @@ Reflex se lanzó en diciembre de 2022 con el nombre de Pynecone.
- **Discusiones de GitHub**: Una excelente manera de hablar sobre las características que deseas agregar o las cosas que te resultan confusas o necesitan aclaración. - **Discusiones de GitHub**: Una excelente manera de hablar sobre las características que deseas agregar o las cosas que te resultan confusas o necesitan aclaración.
- **GitHub Issues**: Las incidencias son una forma excelente de informar de errores. Además, puedes intentar resolver un problema existente y enviar un PR. - **GitHub Issues**: Las incidencias son una forma excelente de informar de errores. Además, puedes intentar resolver un problema existente y enviar un PR.
Buscamos colaboradores, sin importar su nivel o experiencia. Para contribuir consulta [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) Buscamos colaboradores, sin importar su nivel o experiencia. Para contribuir consulta [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## Licencia ## Licencia

View File

@ -35,7 +35,7 @@ Reflex के अंदर के कामकाज को जानने क
## ⚙️ इंस्टॉलेशन (Installation) ## ⚙️ इंस्टॉलेशन (Installation)
एक टर्मिनल खोलें और चलाएं (Python 3.9+ की आवश्यकता है): एक टर्मिनल खोलें और चलाएं (Python 3.10+ की आवश्यकता है):
```bash ```bash
pip install reflex pip install reflex
@ -239,7 +239,7 @@ Reflex में हर सप्ताह नए रिलीज़ और फ
- **GitHub Discussions** (गिटहब चर्चाएँ): उन सुविधाओं के बारे में बात करने का एक शानदार तरीका जिन्हें आप जोड़ना चाहते हैं या ऐसी चीज़ें जो भ्रमित करने वाली हैं/स्पष्टीकरण की आवश्यकता है। - **GitHub Discussions** (गिटहब चर्चाएँ): उन सुविधाओं के बारे में बात करने का एक शानदार तरीका जिन्हें आप जोड़ना चाहते हैं या ऐसी चीज़ें जो भ्रमित करने वाली हैं/स्पष्टीकरण की आवश्यकता है।
- **GitHub Issues** (गिटहब समस्याएं): ये [बग](https://github.com/reflex-dev/reflex/issues) की रिपोर्ट करने का एक शानदार तरीका है। इसके अतिरिक्त, आप किसी मौजूदा समस्या को हल करने का प्रयास कर सकते हैं और एक पीआर सबमिट कर सकते हैं। - **GitHub Issues** (गिटहब समस्याएं): ये [बग](https://github.com/reflex-dev/reflex/issues) की रिपोर्ट करने का एक शानदार तरीका है। इसके अतिरिक्त, आप किसी मौजूदा समस्या को हल करने का प्रयास कर सकते हैं और एक पीआर सबमिट कर सकते हैं।
हम सक्रिय रूप से योगदानकर्ताओं की तलाश कर रहे हैं, चाहे आपका कौशल स्तर या अनुभव कुछ भी हो।योगदान करने के लिए [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) देखें। हम सक्रिय रूप से योगदानकर्ताओं की तलाश कर रहे हैं, चाहे आपका कौशल स्तर या अनुभव कुछ भी हो।योगदान करने के लिए [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) देखें।
## हमारे सभी योगदानकर्ताओं का धन्यवाद: ## हमारे सभी योगदानकर्ताओं का धन्यवाद:

View File

@ -22,7 +22,7 @@
## ⚙️ Installazione ## ⚙️ Installazione
Apri un terminale ed esegui (Richiede Python 3.9+): Apri un terminale ed esegui (Richiede Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -37,7 +37,7 @@ Reflex がどのように動作しているかを知るには、[アーキテク
## ⚙️ インストール ## ⚙️ インストール
ターミナルを開いて以下のコマンドを実行してください。Python 3.9 以上が必要です。): ターミナルを開いて以下のコマンドを実行してください。Python 3.10 以上が必要です。):
```bash ```bash
pip install reflex pip install reflex
@ -222,7 +222,7 @@ app.add_page(index, title="DALL-E")
<div align="center"> <div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp; 📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div> </div>
@ -242,7 +242,7 @@ Reflex は毎週、新しいリリースや機能追加を行っています!
- **GitHub Discussions**: GitHub Discussions では、追加したい機能や、複雑で解明が必要な事柄についての議論に適している場所です。 - **GitHub Discussions**: GitHub Discussions では、追加したい機能や、複雑で解明が必要な事柄についての議論に適している場所です。
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues)はバグの報告に適している場所です。また、課題を解決した PR のサブミットにチャレンジしていただくことも、可能です。 - **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues)はバグの報告に適している場所です。また、課題を解決した PR のサブミットにチャレンジしていただくことも、可能です。
スキルや経験に関わらず、私たちはコントリビュータを積極的に探しています。コントリビュートするために、[CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)をご覧ください。 CONTスキルや経験に関わらず、私たちはコントリビュータを積極的に探しています。コントリビュートするために、[CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)をご覧ください。
## 私たちのコントリビュータに感謝!: ## 私たちのコントリビュータに感謝!:

View File

@ -20,7 +20,7 @@
--- ---
## ⚙️ 설치 ## ⚙️ 설치
터미널을 열고 실행하세요. (Python 3.9+ 필요): 터미널을 열고 실행하세요. (Python 3.10+ 필요):
```bash ```bash
pip install reflex pip install reflex

View File

@ -34,7 +34,7 @@
## ⚙️ Installation - نصب و راه اندازی ## ⚙️ Installation - نصب و راه اندازی
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.9+): یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.10+):
```bash ```bash
pip install reflex pip install reflex
@ -249,7 +249,7 @@ app.add_page(index, title="DALL-E")
- **بحث های GitHub**: راهی عالی برای صحبت در مورد ویژگی هایی که می خواهید اضافه کنید یا چیزهایی که گیج کننده هستند/نیاز به توضیح دارند. - **بحث های GitHub**: راهی عالی برای صحبت در مورد ویژگی هایی که می خواهید اضافه کنید یا چیزهایی که گیج کننده هستند/نیاز به توضیح دارند.
- **قسمت مشکلات GitHub**: [قسمت مشکلات](https://github.com/reflex-dev/reflex/issues) یک راه عالی برای گزارش اشکال هستند. علاوه بر این، می توانید یک مشکل موجود را حل کنید و یک PR(pull request) ارسال کنید. - **قسمت مشکلات GitHub**: [قسمت مشکلات](https://github.com/reflex-dev/reflex/issues) یک راه عالی برای گزارش اشکال هستند. علاوه بر این، می توانید یک مشکل موجود را حل کنید و یک PR(pull request) ارسال کنید.
ما فعالانه به دنبال مشارکت کنندگان هستیم، فارغ از سطح مهارت یا تجربه شما. برای مشارکت [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) را بررسی کنید. ما فعالانه به دنبال مشارکت کنندگان هستیم، فارغ از سطح مهارت یا تجربه شما. برای مشارکت [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) را بررسی کنید.
## All Thanks To Our Contributors - با تشکر از همکاران ما: ## All Thanks To Our Contributors - با تشکر از همکاران ما:

View File

@ -21,7 +21,7 @@
--- ---
## ⚙️ Instalação ## ⚙️ Instalação
Abra um terminal e execute (Requer Python 3.9+): Abra um terminal e execute (Requer Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -24,7 +24,7 @@
## ⚙️ Kurulum ## ⚙️ Kurulum
Bir terminal açın ve çalıştırın (Python 3.9+ gerekir): Bir terminal açın ve çalıştırın (Python 3.10+ gerekir):
```bash ```bash
pip install reflex pip install reflex
@ -200,7 +200,7 @@ Daha fazla sayfa ekleyerek çok sayfalı bir uygulama oluşturabilirsiniz.
<div align="center"> <div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy) &nbsp; 📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy) &nbsp;
</div> </div>
@ -229,7 +229,7 @@ Her boyuttaki katkıları memnuniyetle karşılıyoruz! Aşağıda Reflex toplul
- **GitHub Discussions**: Eklemek istediğiniz özellikler veya kafa karıştırıcı, açıklığa kavuşturulması gereken şeyler hakkında konuşmanın harika bir yolu. - **GitHub Discussions**: Eklemek istediğiniz özellikler veya kafa karıştırıcı, açıklığa kavuşturulması gereken şeyler hakkında konuşmanın harika bir yolu.
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) hataları bildirmenin mükemmel bir yoludur. Ayrıca mevcut bir sorunu deneyip çözebilir ve bir PR (Pull Requests) gönderebilirsiniz. - **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) hataları bildirmenin mükemmel bir yoludur. Ayrıca mevcut bir sorunu deneyip çözebilir ve bir PR (Pull Requests) gönderebilirsiniz.
Beceri düzeyiniz veya deneyiminiz ne olursa olsun aktif olarak katkıda bulunacak kişiler arıyoruz. Katkı sağlamak için katkı sağlama rehberimize bakabilirsiniz: [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) Beceri düzeyiniz veya deneyiminiz ne olursa olsun aktif olarak katkıda bulunacak kişiler arıyoruz. Katkı sağlamak için katkı sağlama rehberimize bakabilirsiniz: [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## Hepsi Katkıda Bulunanlar Sayesinde: ## Hepsi Katkıda Bulunanlar Sayesinde:

View File

@ -34,7 +34,7 @@ Các tính năng chính:
## ⚙️ Cài đặt ## ⚙️ Cài đặt
Mở cửa sổ lệnh và chạy (Yêu cầu Python phiên bản 3.9+): Mở cửa sổ lệnh và chạy (Yêu cầu Python phiên bản 3.10+):
```bash ```bash
pip install reflex pip install reflex
@ -232,7 +232,7 @@ Bạn có thể tạo một ứng dụng nhiều trang bằng cách thêm trang.
<div align="center"> <div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp; 📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div> </div>
@ -254,7 +254,7 @@ Chúng tôi chào đón mọi đóng góp dù lớn hay nhỏ. Dưới đây là
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) là nơi tốt nhất để thông báo. Ngoài ra bạn có thể sửa chữa các vấn đề bằng cách tạo PR. - **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) là nơi tốt nhất để thông báo. Ngoài ra bạn có thể sửa chữa các vấn đề bằng cách tạo PR.
Chúng tôi luôn sẵn sàng tìm kiếm các contributor, bất kể kinh nghiệm. Để tham gia đóng góp, xin mời xem Chúng tôi luôn sẵn sàng tìm kiếm các contributor, bất kể kinh nghiệm. Để tham gia đóng góp, xin mời xem
[CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## Xin cảm ơn các Contributors: ## Xin cảm ơn các Contributors:

View File

@ -34,7 +34,7 @@ Reflex 是一个使用纯Python构建全栈web应用的库。
## ⚙️ 安装 ## ⚙️ 安装
打开一个终端并且运行(要求Python3.9+): 打开一个终端并且运行(要求Python3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -36,7 +36,7 @@ Reflex 是一個可以用純 Python 構建全端網頁應用程式的函式庫
## ⚙️ 安裝 ## ⚙️ 安裝
開啟一個終端機並且執行 (需要 Python 3.9+): 開啟一個終端機並且執行 (需要 Python 3.10+):
```bash ```bash
pip install reflex pip install reflex
@ -229,7 +229,7 @@ app.add_page(index, title="DALL-E")
<div align="center"> <div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp; 📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div> </div>
@ -251,7 +251,7 @@ Reflex 每周都有新功能和釋出新版本! 確保你按下 :star: 和 :eyes
- **GitHub Discussions**: 這是一個討論您想新增的功能或對於一些困惑/需要澄清事項的好方法。 - **GitHub Discussions**: 這是一個討論您想新增的功能或對於一些困惑/需要澄清事項的好方法。
- **GitHub Issues**: 在 [Issues](https://github.com/reflex-dev/reflex/issues) 頁面報告錯誤是一個絕佳的方式。此外,您也可以嘗試解決現有 Issue 並提交 PR。 - **GitHub Issues**: 在 [Issues](https://github.com/reflex-dev/reflex/issues) 頁面報告錯誤是一個絕佳的方式。此外,您也可以嘗試解決現有 Issue 並提交 PR。
我們積極尋找貢獻者,不論您的技能水平或經驗如何。要貢獻,請查看 [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) 我們積極尋找貢獻者,不論您的技能水平或經驗如何。要貢獻,請查看 [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## 感謝所有貢獻者: ## 感謝所有貢獻者:

2638
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "reflex" name = "reflex"
version = "0.6.8dev1" version = "0.7.1dev1"
description = "Web apps in pure Python." description = "Web apps in pure Python."
license = "Apache-2.0" license = "Apache-2.0"
authors = [ authors = [
@ -18,30 +18,27 @@ keywords = ["web", "framework"]
classifiers = ["Development Status :: 4 - Beta"] classifiers = ["Development Status :: 4 - Beta"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.9" python = ">=3.10, <4.0"
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1" fastapi = ">=0.96.0,!=0.111.0,!=0.111.1"
gunicorn = ">=20.1.0,<24.0" gunicorn = ">=20.1.0,<24.0"
jinja2 = ">=3.1.2,<4.0" jinja2 = ">=3.1.2,<4.0"
psutil = ">=5.9.4,<7.0" psutil = ">=5.9.4,<7.0"
pydantic = ">=1.10.2,<3.0" pydantic = ">=1.10.21,<3.0"
python-multipart = ">=0.0.5,<0.1" python-multipart = ">=0.0.5,<0.1"
python-socketio = ">=5.7.0,<6.0" python-socketio = ">=5.7.0,<6.0"
redis = ">=4.3.5,<6.0" redis = ">=4.3.5,<6.0"
rich = ">=13.0.0,<14.0" rich = ">=13.0.0,<14.0"
sqlmodel = ">=0.0.14,<0.1" sqlmodel = ">=0.0.14,<0.1"
typer = ">=0.4.2,<1.0" typer = ">=0.15.1,<1.0"
uvicorn = ">=0.20.0" uvicorn = ">=0.20.0"
starlette-admin = ">=0.11.0,<1.0" starlette-admin = ">=0.11.0,<1.0"
alembic = ">=1.11.1,<2.0" alembic = ">=1.11.1,<2.0"
platformdirs = ">=3.10.0,<5.0" platformdirs = ">=3.10.0,<5.0"
distro = { version = ">=1.8.0,<2.0", platform = "linux" } distro = { version = ">=1.8.0,<2.0", platform = "linux" }
python-engineio = "!=4.6.0" python-engineio = "!=4.6.0"
wrapt = [ wrapt = ">=1.17.0,<2.0"
{ version = ">=1.14.0,<2.0", python = ">=3.11" },
{ version = ">=1.11.0,<2.0", python = "<3.11" },
]
packaging = ">=23.1,<25.0" packaging = ">=23.1,<25.0"
reflex-hosting-cli = ">=0.1.29,<2.0" reflex-hosting-cli = ">=0.1.29"
charset-normalizer = ">=3.3.2,<4.0" charset-normalizer = ">=3.3.2,<4.0"
wheel = ">=0.42.0,<1.0" wheel = ">=0.42.0,<1.0"
build = ">=1.0.3,<2.0" build = ">=1.0.3,<2.0"
@ -49,21 +46,19 @@ setuptools = ">=75.0"
httpx = ">=0.25.1,<1.0" httpx = ">=0.25.1,<1.0"
twine = ">=4.0.0,<7.0" twine = ">=4.0.0,<7.0"
tomlkit = ">=0.12.4,<1.0" tomlkit = ">=0.12.4,<1.0"
asgiproxy = { version = "==0.1.1", optional = true }
lazy_loader = ">=0.4" lazy_loader = ">=0.4"
reflex-chakra = ">=0.6.0"
typing_extensions = ">=4.6.0" typing_extensions = ">=4.6.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest = ">=7.1.2,<9.0" pytest = ">=7.1.2,<9.0"
pytest-mock = ">=3.10.0,<4.0" pytest-mock = ">=3.10.0,<4.0"
pyright = ">=1.1.229,<1.1.335" pyright = ">=1.1.394, <1.2"
darglint = ">=1.8.1,<2.0" darglint = ">=1.8.1,<2.0"
dill = ">=0.3.8" dill = ">=0.3.8"
toml = ">=0.10.2,<1.0" toml = ">=0.10.2,<1.0"
pytest-asyncio = ">=0.24.0" pytest-asyncio = ">=0.24.0"
pytest-cov = ">=4.0.0,<7.0" pytest-cov = ">=4.0.0,<7.0"
ruff = "0.8.2" ruff = "0.9.6"
pandas = ">=2.1.1,<3.0" pandas = ">=2.1.1,<3.0"
pillow = ">=10.0.0,<12.0" pillow = ">=10.0.0,<12.0"
plotly = ">=5.13.0,<6.0" plotly = ">=5.13.0,<6.0"
@ -73,39 +68,70 @@ selenium = ">=4.11.0,<5.0"
pytest-benchmark = ">=4.0.0,<6.0" pytest-benchmark = ">=4.0.0,<6.0"
playwright = ">=1.46.0" playwright = ">=1.46.0"
pytest-playwright = ">=0.5.1" pytest-playwright = ">=0.5.1"
asgiproxy = "==0.1.1" pytest-codspeed = "^3.1.2"
[tool.poetry.scripts] [tool.poetry.scripts]
reflex = "reflex.reflex:cli" reflex = "reflex.reflex:cli"
[tool.poetry.extras]
proxy = ["asgiproxy"]
[build-system] [build-system]
requires = ["poetry-core>=1.5.1"] requires = ["poetry-core>=1.5.1"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.pyright] [tool.pyright]
reportIncompatibleMethodOverride = false
[tool.ruff] [tool.ruff]
target-version = "py39" target-version = "py310"
output-format = "concise" output-format = "concise"
lint.isort.split-on-trailing-comma = false lint.isort.split-on-trailing-comma = false
lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "PERF", "PTH", "RUF", "SIM", "T", "W"] lint.select = [
lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012"] "ANN001",
"B",
"C4",
"D",
"E",
"ERA",
"F",
"FURB",
"I",
"N",
"PERF",
"PGH",
"PTH",
"RUF",
"SIM",
"T",
"TRY",
"W",
]
lint.ignore = [
"B008",
"D205",
"E501",
"F403",
"SIM115",
"RUF006",
"RUF008",
"RUF012",
"TRY0",
]
lint.pydocstyle.convention = "google" lint.pydocstyle.convention = "google"
[tool.ruff.lint.per-file-ignores] [tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"] "__init__.py" = ["F401"]
"tests/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T"] "tests/*.py" = ["ANN001", "D100", "D103", "D104", "B018", "PERF", "T", "N"]
"benchmarks/*.py" = ["ANN001", "D100", "D103", "D104", "B018", "PERF", "T", "N"]
"reflex/.templates/*.py" = ["D100", "D103", "D104"] "reflex/.templates/*.py" = ["D100", "D103", "D104"]
"*.pyi" = ["D301", "D415", "D417", "D418", "E742"] "*.pyi" = ["D301", "D415", "D417", "D418", "E742", "N", "PGH"]
"pyi_generator.py" = ["N802"]
"reflex/constants/*.py" = ["N"]
"*/blank.py" = ["I001"] "*/blank.py" = ["I001"]
[tool.pytest.ini_options] [tool.pytest.ini_options]
filterwarnings = "ignore:fields may not start with an underscore:RuntimeWarning"
asyncio_default_fixture_loop_scope = "function" asyncio_default_fixture_loop_scope = "function"
asyncio_mode = "auto" asyncio_mode = "auto"
[tool.codespell] [tool.codespell]
skip = "docs/*,*.html,examples/*, *.pyi" skip = "docs/*,*.html,examples/*, *.pyi, poetry.lock"
ignore-words-list = "te, TreeE" ignore-words-list = "te, TreeE"

View File

@ -8,7 +8,7 @@ version = "0.0.1"
description = "Reflex custom component {{ module_name }}" description = "Reflex custom component {{ module_name }}"
readme = "README.md" readme = "README.md"
license = { text = "Apache-2.0" } license = { text = "Apache-2.0" }
requires-python = ">=3.9" requires-python = ">=3.10"
authors = [{ name = "", email = "YOUREMAIL@domain.com" }] authors = [{ name = "", email = "YOUREMAIL@domain.com" }]
keywords = ["reflex","reflex-custom-components"] keywords = ["reflex","reflex-custom-components"]

View File

@ -38,13 +38,13 @@ export default function MyApp({ Component, pageProps }) {
}, []); }, []);
return ( return (
<ThemeProvider defaultTheme={ defaultColorMode } attribute="class"> <ThemeProvider defaultTheme={ defaultColorMode } attribute="class">
<AppWrap> <StateProvider>
<StateProvider> <EventLoopProvider>
<EventLoopProvider> <AppWrap>
<Component {...pageProps} /> <Component {...pageProps} />
</EventLoopProvider> </AppWrap>
</StateProvider> </EventLoopProvider>
</AppWrap> </StateProvider>
</ThemeProvider> </ThemeProvider>
); );
} }

View File

@ -60,7 +60,7 @@
{# Args: #} {# Args: #}
{# component: component dictionary #} {# component: component dictionary #}
{% macro render_iterable_tag(component) %} {% macro render_iterable_tag(component) %}
<>{ {%- if component.iterable_type == 'dict' -%}Object.entries({{- component.iterable_state }}){%- else -%}{{- component.iterable_state }}{%- endif -%}.map(({{ component.arg_name }}, {{ component.arg_index }}) => ( <>{ {{ component.iterable_state }}.map(({{ component.arg_name }}, {{ component.arg_index }}) => (
{% for child in component.children %} {% for child in component.children %}
{{ render(child) }} {{ render(child) }}
{% endfor %} {% endfor %}
@ -86,11 +86,11 @@
{% for condition in case[:-1] %} {% for condition in case[:-1] %}
case JSON.stringify({{ condition._js_expr }}): case JSON.stringify({{ condition._js_expr }}):
{% endfor %} {% endfor %}
return {{ case[-1] }}; return {{ render(case[-1]) }};
break; break;
{% endfor %} {% endfor %}
default: default:
return {{ component.default }}; return {{ render(component.default) }};
break; break;
} }
})() })()

View File

@ -10,16 +10,15 @@ import {
export default function RadixThemesColorModeProvider({ children }) { export default function RadixThemesColorModeProvider({ children }) {
const { theme, resolvedTheme, setTheme } = useTheme(); const { theme, resolvedTheme, setTheme } = useTheme();
const [rawColorMode, setRawColorMode] = useState(defaultColorMode); const [rawColorMode, setRawColorMode] = useState(defaultColorMode);
const [resolvedColorMode, setResolvedColorMode] = useState("dark"); const [resolvedColorMode, setResolvedColorMode] = useState(
defaultColorMode === "dark" ? "dark" : "light"
);
useEffect(() => { useEffect(() => {
if (isDevMode) { if (isDevMode) {
const lastCompiledTimeInLocalStorage = const lastCompiledTimeInLocalStorage =
localStorage.getItem("last_compiled_time"); localStorage.getItem("last_compiled_time");
if ( if (lastCompiledTimeInLocalStorage !== lastCompiledTimeStamp) {
lastCompiledTimeInLocalStorage &&
lastCompiledTimeInLocalStorage !== lastCompiledTimeStamp
) {
// on app startup, make sure the application color mode is persisted correctly. // on app startup, make sure the application color mode is persisted correctly.
setTheme(defaultColorMode); setTheme(defaultColorMode);
localStorage.setItem("last_compiled_time", lastCompiledTimeStamp); localStorage.setItem("last_compiled_time", lastCompiledTimeStamp);

View File

@ -3,6 +3,7 @@ import axios from "axios";
import io from "socket.io-client"; import io from "socket.io-client";
import JSON5 from "json5"; import JSON5 from "json5";
import env from "$/env.json"; import env from "$/env.json";
import reflexEnvironment from "$/reflex.json";
import Cookies from "universal-cookie"; import Cookies from "universal-cookie";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import Router, { useRouter } from "next/router"; import Router, { useRouter } from "next/router";
@ -105,6 +106,18 @@ export const getBackendURL = (url_str) => {
return endpoint; return endpoint;
}; };
/**
* Check if the backend is disabled.
*
* @returns True if the backend is disabled, false otherwise.
*/
export const isBackendDisabled = () => {
const cookie = document.cookie
.split("; ")
.find((row) => row.startsWith("backend-enabled="));
return cookie !== undefined && cookie.split("=")[1] == "false";
};
/** /**
* Determine if any event in the event queue is stateful. * Determine if any event in the event queue is stateful.
* *
@ -404,11 +417,19 @@ export const connect = async (
socket.current = io(endpoint.href, { socket.current = io(endpoint.href, {
path: endpoint["pathname"], path: endpoint["pathname"],
transports: transports, transports: transports,
protocols: [reflexEnvironment.version],
autoUnref: false, autoUnref: false,
query: { token: getToken() }, query: { token: getToken() },
}); });
// Ensure undefined fields in events are sent as null instead of removed // Ensure undefined fields in events are sent as null instead of removed
socket.current.io.encoder.replacer = (k, v) => (v === undefined ? null : v); socket.current.io.encoder.replacer = (k, v) => (v === undefined ? null : v);
socket.current.io.decoder.tryParse = (str) => {
try {
return JSON5.parse(str);
} catch (e) {
return false;
}
};
function checkVisibility() { function checkVisibility() {
if (document.visibilityState === "visible") { if (document.visibilityState === "visible") {
@ -801,14 +822,10 @@ export const useEventLoop = (
}; };
}, []); }, []);
// Main event loop. // Handle socket connect/disconnect.
useEffect(() => { useEffect(() => {
// Skip if the router is not ready. // only use websockets if state is present and backend is not disabled (reflex cloud).
if (!router.isReady) { if (Object.keys(initialState).length > 1 && !isBackendDisabled()) {
return;
}
// only use websockets if state is present
if (Object.keys(initialState).length > 1) {
// Initialize the websocket connection. // Initialize the websocket connection.
if (!socket.current) { if (!socket.current) {
connect( connect(
@ -819,13 +836,28 @@ export const useEventLoop = (
client_storage client_storage
); );
} }
(async () => {
// Process all outstanding events.
while (event_queue.length > 0 && !event_processing) {
await processEvent(socket.current);
}
})();
} }
// Cleanup function.
return () => {
if (socket.current) {
socket.current.disconnect();
}
};
}, []);
// Main event loop.
useEffect(() => {
// Skip if the router is not ready.
if (!router.isReady || isBackendDisabled()) {
return;
}
(async () => {
// Process all outstanding events.
while (event_queue.length > 0 && !event_processing) {
await processEvent(socket.current);
}
})();
}); });
// localStorage event handling // localStorage event handling

View File

@ -84,6 +84,9 @@ In the example above, you will be able to do `rx.list`
from __future__ import annotations from __future__ import annotations
from types import ModuleType
from typing import Any
from reflex.utils import ( from reflex.utils import (
compat, # for side-effects compat, # for side-effects
lazy_loader, lazy_loader,
@ -245,6 +248,7 @@ COMPONENTS_CORE_MAPPING: dict = {
"selected_files", "selected_files",
"upload", "upload",
], ],
"components.core.auto_scroll": ["auto_scroll"],
} }
COMPONENTS_BASE_MAPPING: dict = { COMPONENTS_BASE_MAPPING: dict = {
@ -303,7 +307,6 @@ _MAPPING: dict = {
"event": [ "event": [
"EventChain", "EventChain",
"EventHandler", "EventHandler",
"background",
"call_script", "call_script",
"call_function", "call_function",
"run_script", "run_script",
@ -366,20 +369,5 @@ getattr, __dir__, __all__ = lazy_loader.attach(
) )
def __getattr__(name): def __getattr__(name: ModuleType | Any):
if name == "chakra":
from reflex.utils import console
console.deprecate(
"rx.chakra",
reason="and moved to a separate package. "
"To continue using Chakra UI components, install the `reflex-chakra` package via `pip install "
"reflex-chakra`.",
deprecation_version="0.6.0",
removal_version="0.7.0",
dedupe=True,
)
import reflex_chakra as rc
return rc
return getattr(name) return getattr(name)

View File

@ -34,6 +34,7 @@ from .components.component import Component as Component
from .components.component import ComponentNamespace as ComponentNamespace from .components.component import ComponentNamespace as ComponentNamespace
from .components.component import NoSSRComponent as NoSSRComponent from .components.component import NoSSRComponent as NoSSRComponent
from .components.component import memo as memo from .components.component import memo as memo
from .components.core.auto_scroll import auto_scroll as auto_scroll
from .components.core.banner import connection_banner as connection_banner from .components.core.banner import connection_banner as connection_banner
from .components.core.banner import connection_modal as connection_modal from .components.core.banner import connection_modal as connection_modal
from .components.core.breakpoints import breakpoints as breakpoints from .components.core.breakpoints import breakpoints as breakpoints
@ -131,7 +132,7 @@ from .components.radix.themes.layout.container import container as container
from .components.radix.themes.layout.flex import flex as flex from .components.radix.themes.layout.flex import flex as flex
from .components.radix.themes.layout.grid import grid as grid from .components.radix.themes.layout.grid import grid as grid
from .components.radix.themes.layout.list import list_item as list_item from .components.radix.themes.layout.list import list_item as list_item
from .components.radix.themes.layout.list import list_ns as list # noqa from .components.radix.themes.layout.list import list_ns as list # noqa: F401
from .components.radix.themes.layout.list import ordered_list as ordered_list from .components.radix.themes.layout.list import ordered_list as ordered_list
from .components.radix.themes.layout.list import unordered_list as unordered_list from .components.radix.themes.layout.list import unordered_list as unordered_list
from .components.radix.themes.layout.section import section as section from .components.radix.themes.layout.section import section as section
@ -156,7 +157,6 @@ from .constants import Env as Env
from .constants.colors import Color as Color from .constants.colors import Color as Color
from .event import EventChain as EventChain from .event import EventChain as EventChain
from .event import EventHandler as EventHandler from .event import EventHandler as EventHandler
from .event import background as background
from .event import call_function as call_function from .event import call_function as call_function
from .event import call_script as call_script from .event import call_script as call_script
from .event import clear_local_storage as clear_local_storage from .event import clear_local_storage as clear_local_storage

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ from typing import Callable, Coroutine, Set, Union
from fastapi import FastAPI from fastapi import FastAPI
from reflex.utils import console from reflex.utils import console
from reflex.utils.exceptions import InvalidLifespanTaskType from reflex.utils.exceptions import InvalidLifespanTaskTypeError
from .mixin import AppMixin from .mixin import AppMixin
@ -32,7 +32,7 @@ class LifespanMixin(AppMixin):
try: try:
async with contextlib.AsyncExitStack() as stack: async with contextlib.AsyncExitStack() as stack:
for task in self.lifespan_tasks: for task in self.lifespan_tasks:
run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # type: ignore run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # pyright: ignore [reportAttributeAccessIssue]
if isinstance(task, asyncio.Task): if isinstance(task, asyncio.Task):
running_tasks.append(task) running_tasks.append(task)
else: else:
@ -61,19 +61,19 @@ class LifespanMixin(AppMixin):
Args: Args:
task: The task to register. task: The task to register.
task_kwargs: The kwargs of the task. **task_kwargs: The kwargs of the task.
Raises: Raises:
InvalidLifespanTaskType: If the task is a generator function. InvalidLifespanTaskTypeError: If the task is a generator function.
""" """
if inspect.isgeneratorfunction(task) or inspect.isasyncgenfunction(task): if inspect.isgeneratorfunction(task) or inspect.isasyncgenfunction(task):
raise InvalidLifespanTaskType( raise InvalidLifespanTaskTypeError(
f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager." f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager."
) )
if task_kwargs: if task_kwargs:
original_task = task original_task = task
task = functools.partial(task, **task_kwargs) # type: ignore task = functools.partial(task, **task_kwargs) # pyright: ignore [reportArgumentType]
functools.update_wrapper(task, original_task) # type: ignore functools.update_wrapper(task, original_task) # pyright: ignore [reportArgumentType]
self.lifespan_tasks.add(task) # type: ignore self.lifespan_tasks.add(task)
console.debug(f"Registered lifespan task: {task.__name__}") # type: ignore console.debug(f"Registered lifespan task: {task.__name__}") # pyright: ignore [reportAttributeAccessIssue]

View File

@ -53,11 +53,11 @@ class MiddlewareMixin(AppMixin):
""" """
for middleware in self.middleware: for middleware in self.middleware:
if asyncio.iscoroutinefunction(middleware.preprocess): if asyncio.iscoroutinefunction(middleware.preprocess):
out = await middleware.preprocess(app=self, state=state, event=event) # type: ignore out = await middleware.preprocess(app=self, state=state, event=event) # pyright: ignore [reportArgumentType]
else: else:
out = middleware.preprocess(app=self, state=state, event=event) # type: ignore out = middleware.preprocess(app=self, state=state, event=event) # pyright: ignore [reportArgumentType]
if out is not None: if out is not None:
return out # type: ignore return out # pyright: ignore [reportReturnType]
async def _postprocess( async def _postprocess(
self, state: BaseState, event: Event, update: StateUpdate self, state: BaseState, event: Event, update: StateUpdate
@ -78,18 +78,18 @@ class MiddlewareMixin(AppMixin):
for middleware in self.middleware: for middleware in self.middleware:
if asyncio.iscoroutinefunction(middleware.postprocess): if asyncio.iscoroutinefunction(middleware.postprocess):
out = await middleware.postprocess( out = await middleware.postprocess(
app=self, # type: ignore app=self, # pyright: ignore [reportArgumentType]
state=state, state=state,
event=event, event=event,
update=update, update=update,
) )
else: else:
out = middleware.postprocess( out = middleware.postprocess(
app=self, # type: ignore app=self, # pyright: ignore [reportArgumentType]
state=state, state=state,
event=event, event=event,
update=update, update=update,
) )
if out is not None: if out is not None:
return out # type: ignore return out # pyright: ignore [reportReturnType]
return update return update

View File

@ -5,16 +5,13 @@ Only the app attribute is explicitly exposed.
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from reflex import constants from reflex import constants
from reflex.utils import telemetry
from reflex.utils.exec import is_prod_mode from reflex.utils.exec import is_prod_mode
from reflex.utils.prerequisites import get_app from reflex.utils.prerequisites import get_and_validate_app
if constants.CompileVars.APP != "app": if constants.CompileVars.APP != "app":
raise AssertionError("unexpected variable name for 'app'") raise AssertionError("unexpected variable name for 'app'")
telemetry.send("compile") app, app_module = get_and_validate_app(reload=False)
app_module = get_app(reload=False)
app = getattr(app_module, constants.CompileVars.APP)
# For py3.9 compatibility when redis is used, we MUST add any decorator pages # For py3.9 compatibility when redis is used, we MUST add any decorator pages
# before compiling the app in a thread to avoid event loop error (REF-2172). # before compiling the app in a thread to avoid event loop error (REF-2172).
app._apply_decorated_pages() app._apply_decorated_pages()
@ -30,8 +27,7 @@ if is_prod_mode():
# ensure only "app" is exposed. # ensure only "app" is exposed.
del app_module del app_module
del compile_future del compile_future
del get_app del get_and_validate_app
del is_prod_mode del is_prod_mode
del telemetry
del constants del constants
del ThreadPoolExecutor del ThreadPoolExecutor

View File

@ -5,15 +5,9 @@ from __future__ import annotations
import os import os
from typing import TYPE_CHECKING, Any, List, Type from typing import TYPE_CHECKING, Any, List, Type
try: import pydantic.v1.main as pydantic_main
import pydantic.v1.main as pydantic_main from pydantic.v1 import BaseModel
from pydantic.v1 import BaseModel from pydantic.v1.fields import ModelField
from pydantic.v1.fields import ModelField
except ModuleNotFoundError:
if not TYPE_CHECKING:
import pydantic.main as pydantic_main
from pydantic import BaseModel
from pydantic.fields import ModelField # type: ignore
def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None: def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None:
@ -44,13 +38,13 @@ def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None
# monkeypatch pydantic validate_field_name method to skip validating # monkeypatch pydantic validate_field_name method to skip validating
# shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True) # shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
pydantic_main.validate_field_name = validate_field_name # type: ignore pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPossiblyUnboundVariable, reportPrivateImportUsage]
if TYPE_CHECKING: if TYPE_CHECKING:
from reflex.vars import Var from reflex.vars import Var
class Base(BaseModel): # pyright: ignore [reportUnboundVariable] class Base(BaseModel):
"""The base class subclassed by all Reflex classes. """The base class subclassed by all Reflex classes.
This class wraps Pydantic and provides common methods such as This class wraps Pydantic and provides common methods such as
@ -75,12 +69,12 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
""" """
from reflex.utils.serializers import serialize from reflex.utils.serializers import serialize
return self.__config__.json_dumps( # type: ignore return self.__config__.json_dumps(
self.dict(), self.dict(),
default=serialize, default=serialize,
) )
def set(self, **kwargs): def set(self, **kwargs: Any):
"""Set multiple fields and return the object. """Set multiple fields and return the object.
Args: Args:
@ -113,12 +107,12 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
default_value: The default value of the field default_value: The default value of the field
""" """
var_name = var._var_field_name var_name = var._var_field_name
new_field = ModelField.infer( new_field = ModelField.infer( # pyright: ignore [reportPossiblyUnboundVariable]
name=var_name, name=var_name,
value=default_value, value=default_value,
annotation=var._var_type, annotation=var._var_type,
class_validators=None, class_validators=None,
config=cls.__config__, # type: ignore config=cls.__config__,
) )
cls.__fields__.update({var_name: new_field}) cls.__fields__.update({var_name: new_field})

View File

@ -4,7 +4,7 @@ from __future__ import annotations
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, Dict, Iterable, Optional, Tuple, Type, Union from typing import TYPE_CHECKING, Dict, Iterable, Optional, Sequence, Tuple, Type, Union
from reflex import constants from reflex import constants
from reflex.compiler import templates, utils from reflex.compiler import templates, utils
@ -78,6 +78,7 @@ def _compile_app(app_root: Component) -> str:
hooks=app_root._get_all_hooks(), hooks=app_root._get_all_hooks(),
window_libraries=window_libraries, window_libraries=window_libraries,
render=app_root.render(), render=app_root.render(),
dynamic_imports=app_root._get_all_dynamic_imports(),
) )
@ -239,11 +240,19 @@ def _compile_components(
component_renders.append(component_render) component_renders.append(component_render)
imports = utils.merge_imports(imports, component_imports) imports = utils.merge_imports(imports, component_imports)
dynamic_imports = {
comp_import: None
for comp_render in component_renders
if "dynamic_imports" in comp_render
for comp_import in comp_render["dynamic_imports"]
}
# Compile the components page. # Compile the components page.
return ( return (
templates.COMPONENTS.render( templates.COMPONENTS.render(
imports=utils.compile_imports(imports), imports=utils.compile_imports(imports),
components=component_renders, components=component_renders,
dynamic_imports=dynamic_imports,
), ),
imports, imports,
) )
@ -499,7 +508,7 @@ def compile_tailwind(
The compiled Tailwind config. The compiled Tailwind config.
""" """
# Get the path for the output file. # Get the path for the output file.
output_path = get_web_dir() / constants.Tailwind.CONFIG output_path = str((get_web_dir() / constants.Tailwind.CONFIG).absolute())
# Compile the config. # Compile the config.
code = _compile_tailwind(config) code = _compile_tailwind(config)
@ -536,7 +545,47 @@ def purge_web_pages_dir():
if TYPE_CHECKING: if TYPE_CHECKING:
from reflex.app import UnevaluatedPage from reflex.app import ComponentCallable, UnevaluatedPage
def _into_component_once(component: Component | ComponentCallable) -> Component | None:
"""Convert a component to a Component.
Args:
component: The component to convert.
Returns:
The converted component.
"""
if isinstance(component, Component):
return component
if isinstance(component, (Var, int, float, str)):
return Fragment.create(component)
if isinstance(component, Sequence):
return Fragment.create(*component)
return None
def into_component(component: Component | ComponentCallable) -> Component:
"""Convert a component to a Component.
Args:
component: The component to convert.
Returns:
The converted component.
Raises:
TypeError: If the component is not a Component.
"""
if (converted := _into_component_once(component)) is not None:
return converted
if (
callable(component)
and (converted := _into_component_once(component())) is not None
):
return converted
raise TypeError(f"Expected a Component, got {type(component)}")
def compile_unevaluated_page( def compile_unevaluated_page(
@ -559,12 +608,7 @@ def compile_unevaluated_page(
The compiled component and whether state should be enabled. The compiled component and whether state should be enabled.
""" """
# Generate the component if it is a callable. # Generate the component if it is a callable.
component = page.component component = into_component(page.component)
component = component if isinstance(component, Component) else component()
# unpack components that return tuples in an rx.fragment.
if isinstance(component, tuple):
component = Fragment.create(*component)
component._add_style_recursive(style or {}, theme) component._add_style_recursive(style or {}, theme)
@ -669,10 +713,8 @@ class ExecutorSafeFunctions:
The route, compiled component, and compiled page. The route, compiled component, and compiled page.
""" """
component, enable_state = compile_unevaluated_page( component, enable_state = compile_unevaluated_page(
route, cls.UNCOMPILED_PAGES[route] route, cls.UNCOMPILED_PAGES[route], cls.STATE, style, theme
) )
component = component if isinstance(component, Component) else component()
component._add_style_recursive(style, theme)
return route, component, compile_page(route, component, cls.STATE) return route, component, compile_page(route, component, cls.STATE)
@classmethod @classmethod

View File

@ -48,11 +48,10 @@ class ReflexJinjaEnvironment(Environment):
def __init__(self) -> None: def __init__(self) -> None:
"""Set default environment.""" """Set default environment."""
extensions = ["jinja2.ext.debug"]
super().__init__( super().__init__(
extensions=extensions,
trim_blocks=True, trim_blocks=True,
lstrip_blocks=True, lstrip_blocks=True,
auto_reload=False,
) )
self.filters["json_dumps"] = json_dumps self.filters["json_dumps"] = json_dumps
self.filters["react_setter"] = lambda state: f"set{state.capitalize()}" self.filters["react_setter"] = lambda state: f"set{state.capitalize()}"

View File

@ -2,17 +2,15 @@
from __future__ import annotations from __future__ import annotations
import asyncio
import concurrent.futures
import traceback
from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Dict, Optional, Type, Union from typing import Any, Callable, Dict, Optional, Type, Union
from urllib.parse import urlparse from urllib.parse import urlparse
from reflex.utils.prerequisites import get_web_dir from pydantic.v1.fields import ModelField
from reflex.vars.base import Var
try:
from pydantic.v1.fields import ModelField
except ModuleNotFoundError:
from pydantic.fields import ModelField # type: ignore
from reflex import constants from reflex import constants
from reflex.components.base import ( from reflex.components.base import (
@ -29,10 +27,13 @@ from reflex.components.base import (
) )
from reflex.components.component import Component, ComponentStyle, CustomComponent from reflex.components.component import Component, ComponentStyle, CustomComponent
from reflex.istate.storage import Cookie, LocalStorage, SessionStorage from reflex.istate.storage import Cookie, LocalStorage, SessionStorage
from reflex.state import BaseState from reflex.state import BaseState, _resolve_delta
from reflex.style import Style from reflex.style import Style
from reflex.utils import console, format, imports, path_ops from reflex.utils import console, format, imports, path_ops
from reflex.utils.exec import is_in_app_harness
from reflex.utils.imports import ImportVar, ParsedImportDict from reflex.utils.imports import ImportVar, ParsedImportDict
from reflex.utils.prerequisites import get_web_dir
from reflex.vars.base import Var
# To re-export this function. # To re-export this function.
merge_imports = imports.merge_imports merge_imports = imports.merge_imports
@ -112,24 +113,34 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
validate_imports(collapsed_import_dict) validate_imports(collapsed_import_dict)
import_dicts = [] import_dicts = []
for lib, fields in collapsed_import_dict.items(): for lib, fields in collapsed_import_dict.items():
default, rest = compile_import_statement(fields)
# prevent lib from being rendered on the page if all imports are non rendered kind # prevent lib from being rendered on the page if all imports are non rendered kind
if not any(f.render for f in fields): # type: ignore if not any(f.render for f in fields):
continue continue
if not lib: lib_paths: dict[str, list[ImportVar]] = {}
if default:
raise ValueError("No default field allowed for empty library.")
if rest is None or len(rest) == 0:
raise ValueError("No fields to import.")
import_dicts.extend(get_import_dict(module) for module in sorted(rest))
continue
# remove the version before rendering the package imports for field in fields:
lib = format.format_library_name(lib) lib_paths.setdefault(field.package_path, []).append(field)
import_dicts.append(get_import_dict(lib, default, rest)) compiled = {
path: compile_import_statement(fields) for path, fields in lib_paths.items()
}
for path, (default, rest) in compiled.items():
if not lib:
if default:
raise ValueError("No default field allowed for empty library.")
if rest is None or len(rest) == 0:
raise ValueError("No fields to import.")
import_dicts.extend(get_import_dict(module) for module in sorted(rest))
continue
# remove the version before rendering the package imports
formatted_lib = format.format_library_name(lib) + (
path if path != "/" else ""
)
import_dicts.append(get_import_dict(formatted_lib, default, rest))
return import_dicts return import_dicts
@ -151,6 +162,22 @@ def get_import_dict(lib: str, default: str = "", rest: list[str] | None = None)
} }
def save_error(error: Exception) -> str:
"""Save the error to a file.
Args:
error: The error to save.
Returns:
The path of the saved error.
"""
timestamp = datetime.now().strftime("%Y-%m-%d__%H-%M-%S")
constants.Reflex.LOGS_DIR.mkdir(parents=True, exist_ok=True)
log_path = constants.Reflex.LOGS_DIR / f"error_{timestamp}.log"
traceback.TracebackException.from_exception(error).print(file=log_path.open("w+"))
return str(log_path)
def compile_state(state: Type[BaseState]) -> dict: def compile_state(state: Type[BaseState]) -> dict:
"""Compile the state of the app. """Compile the state of the app.
@ -163,13 +190,31 @@ def compile_state(state: Type[BaseState]) -> dict:
try: try:
initial_state = state(_reflex_internal_init=True).dict(initial=True) initial_state = state(_reflex_internal_init=True).dict(initial=True)
except Exception as e: except Exception as e:
log_path = save_error(e)
console.warn( console.warn(
f"Failed to compile initial state with computed vars, excluding them: {e}" f"Failed to compile initial state with computed vars. Error log saved to {log_path}"
) )
initial_state = state(_reflex_internal_init=True).dict( initial_state = state(_reflex_internal_init=True).dict(
initial=True, include_computed=False initial=True, include_computed=False
) )
return initial_state try:
_ = asyncio.get_running_loop()
except RuntimeError:
pass
else:
if is_in_app_harness():
# Playwright tests already have an event loop running, so we can't use asyncio.run.
with concurrent.futures.ThreadPoolExecutor() as pool:
resolved_initial_state = pool.submit(
asyncio.run, _resolve_delta(initial_state)
).result()
console.warn(
f"Had to get initial state in a thread 🤮 {resolved_initial_state}",
)
return resolved_initial_state
# Normally the compile runs before any event loop starts, we asyncio.run is available for calling.
return asyncio.run(_resolve_delta(initial_state))
def _compile_client_storage_field( def _compile_client_storage_field(
@ -292,6 +337,7 @@ def compile_custom_component(
"render": render.render(), "render": render.render(),
"hooks": render._get_all_hooks(), "hooks": render._get_all_hooks(),
"custom_code": render._get_all_custom_code(), "custom_code": render._get_all_custom_code(),
"dynamic_imports": render._get_all_dynamic_imports(),
}, },
imports, imports,
) )
@ -471,6 +517,8 @@ def write_page(path: str | Path, code: str):
""" """
path = Path(path) path = Path(path)
path_ops.mkdir(path.parent) path_ops.mkdir(path.parent)
if path.exists() and path.read_text(encoding="utf-8") == code:
return
path.write_text(code, encoding="utf-8") path.write_text(code, encoding="utf-8")
@ -494,7 +542,7 @@ def empty_dir(path: str | Path, keep_files: list[str] | None = None):
path_ops.rm(element) path_ops.rm(element)
def is_valid_url(url) -> bool: def is_valid_url(url: str) -> bool:
"""Check if a url is valid. """Check if a url is valid.
Args: Args:

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.base.fragment import Fragment from reflex.components.base.fragment import Fragment
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -22,21 +22,21 @@ class AppWrap(Fragment):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "AppWrap": ) -> "AppWrap":
"""Create a new AppWrap component. """Create a new AppWrap component.

View File

@ -2,14 +2,54 @@
from __future__ import annotations from __future__ import annotations
from typing import Any, Iterator from typing import Any, Iterator, Sequence
from reflex.components.component import Component, LiteralComponentVar from reflex.components.component import BaseComponent, Component, ComponentStyle
from reflex.components.tags import Tag from reflex.components.tags import Tag
from reflex.components.tags.tagless import Tagless from reflex.components.tags.tagless import Tagless
from reflex.config import PerformanceMode, environment
from reflex.utils import console
from reflex.utils.decorator import once
from reflex.utils.imports import ParsedImportDict from reflex.utils.imports import ParsedImportDict
from reflex.vars import BooleanVar, ObjectVar, Var from reflex.vars import BooleanVar, ObjectVar, Var
from reflex.vars.base import VarData from reflex.vars.base import GLOBAL_CACHE, VarData
from reflex.vars.sequence import LiteralStringVar
@once
def get_performance_mode():
"""Get the performance mode.
Returns:
The performance mode.
"""
return environment.REFLEX_PERF_MODE.get()
def validate_str(value: str):
"""Validate a string value.
Args:
value: The value to validate.
Raises:
ValueError: If the value is a Var and the performance mode is set to raise.
"""
perf_mode = get_performance_mode()
if perf_mode != PerformanceMode.OFF and value.startswith("reflex___state"):
if perf_mode == PerformanceMode.WARN:
console.warn(
f"Output includes {value!s} which will be displayed as a string. If you are calling `str` on a Var, consider using .to_string() instead."
)
elif perf_mode == PerformanceMode.RAISE:
raise ValueError(
f"Output includes {value!s} which will be displayed as a string. If you are calling `str` on a Var, consider using .to_string() instead."
)
def _components_from_var(var: Var) -> Sequence[BaseComponent]:
var_data = var._get_all_var_data()
return var_data.components if var_data else ()
class Bare(Component): class Bare(Component):
@ -28,10 +68,15 @@ class Bare(Component):
The component. The component.
""" """
if isinstance(contents, Var): if isinstance(contents, Var):
if isinstance(contents, LiteralStringVar):
validate_str(contents._var_value)
return cls(contents=contents) return cls(contents=contents)
else: else:
if isinstance(contents, str):
validate_str(contents)
contents = str(contents) if contents is not None else "" contents = str(contents) if contents is not None else ""
return cls(contents=contents) # type: ignore
return cls(contents=contents)
def _get_all_hooks_internal(self) -> dict[str, VarData | None]: def _get_all_hooks_internal(self) -> dict[str, VarData | None]:
"""Include the hooks for the component. """Include the hooks for the component.
@ -40,8 +85,9 @@ class Bare(Component):
The hooks for the component. The hooks for the component.
""" """
hooks = super()._get_all_hooks_internal() hooks = super()._get_all_hooks_internal()
if isinstance(self.contents, LiteralComponentVar): if isinstance(self.contents, Var):
hooks |= self.contents._var_value._get_all_hooks_internal() for component in _components_from_var(self.contents):
hooks |= component._get_all_hooks_internal()
return hooks return hooks
def _get_all_hooks(self) -> dict[str, VarData | None]: def _get_all_hooks(self) -> dict[str, VarData | None]:
@ -51,18 +97,22 @@ class Bare(Component):
The hooks for the component. The hooks for the component.
""" """
hooks = super()._get_all_hooks() hooks = super()._get_all_hooks()
if isinstance(self.contents, LiteralComponentVar): if isinstance(self.contents, Var):
hooks |= self.contents._var_value._get_all_hooks() for component in _components_from_var(self.contents):
hooks |= component._get_all_hooks()
return hooks return hooks
def _get_all_imports(self) -> ParsedImportDict: def _get_all_imports(self, collapse: bool = False) -> ParsedImportDict:
"""Include the imports for the component. """Include the imports for the component.
Args:
collapse: Whether to collapse the imports.
Returns: Returns:
The imports for the component. The imports for the component.
""" """
imports = super()._get_all_imports() imports = super()._get_all_imports(collapse=collapse)
if isinstance(self.contents, LiteralComponentVar): if isinstance(self.contents, Var):
var_data = self.contents._get_all_var_data() var_data = self.contents._get_all_var_data()
if var_data: if var_data:
imports |= {k: list(v) for k, v in var_data.imports} imports |= {k: list(v) for k, v in var_data.imports}
@ -75,8 +125,9 @@ class Bare(Component):
The dynamic imports. The dynamic imports.
""" """
dynamic_imports = super()._get_all_dynamic_imports() dynamic_imports = super()._get_all_dynamic_imports()
if isinstance(self.contents, LiteralComponentVar): if isinstance(self.contents, Var):
dynamic_imports |= self.contents._var_value._get_all_dynamic_imports() for component in _components_from_var(self.contents):
dynamic_imports |= component._get_all_dynamic_imports()
return dynamic_imports return dynamic_imports
def _get_all_custom_code(self) -> set[str]: def _get_all_custom_code(self) -> set[str]:
@ -86,10 +137,24 @@ class Bare(Component):
The custom code. The custom code.
""" """
custom_code = super()._get_all_custom_code() custom_code = super()._get_all_custom_code()
if isinstance(self.contents, LiteralComponentVar): if isinstance(self.contents, Var):
custom_code |= self.contents._var_value._get_all_custom_code() for component in _components_from_var(self.contents):
custom_code |= component._get_all_custom_code()
return custom_code return custom_code
def _get_all_app_wrap_components(self) -> dict[tuple[int, str], Component]:
"""Get the components that should be wrapped in the app.
Returns:
The components that should be wrapped in the app.
"""
app_wrap_components = super()._get_all_app_wrap_components()
if isinstance(self.contents, Var):
for component in _components_from_var(self.contents):
if isinstance(component, Component):
app_wrap_components |= component._get_all_app_wrap_components()
return app_wrap_components
def _get_all_refs(self) -> set[str]: def _get_all_refs(self) -> set[str]:
"""Get the refs for the children of the component. """Get the refs for the children of the component.
@ -97,8 +162,9 @@ class Bare(Component):
The refs for the children. The refs for the children.
""" """
refs = super()._get_all_refs() refs = super()._get_all_refs()
if isinstance(self.contents, LiteralComponentVar): if isinstance(self.contents, Var):
refs |= self.contents._var_value._get_all_refs() for component in _components_from_var(self.contents):
refs |= component._get_all_refs()
return refs return refs
def _render(self) -> Tag: def _render(self) -> Tag:
@ -108,6 +174,33 @@ class Bare(Component):
return Tagless(contents=f"{{{self.contents!s}}}") return Tagless(contents=f"{{{self.contents!s}}}")
return Tagless(contents=str(self.contents)) return Tagless(contents=str(self.contents))
def _add_style_recursive(
self, style: ComponentStyle, theme: Component | None = None
) -> Component:
"""Add style to the component and its children.
Args:
style: The style to add.
theme: The theme to add.
Returns:
The component with the style added.
"""
new_self = super()._add_style_recursive(style, theme)
are_components_touched = False
if isinstance(self.contents, Var):
for component in _components_from_var(self.contents):
if isinstance(component, Component):
component._add_style_recursive(style, theme)
are_components_touched = True
if are_components_touched:
GLOBAL_CACHE.clear()
return new_self
def _get_vars( def _get_vars(
self, include_children: bool = False, ignore_ids: set[int] | None = None self, include_children: bool = False, ignore_ids: set[int] | None = None
) -> Iterator[Var]: ) -> Iterator[Var]:

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -22,21 +22,21 @@ class Body(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Body": ) -> "Body":
"""Create the component. """Create the component.

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -22,21 +22,21 @@ class NextDocumentLib(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "NextDocumentLib": ) -> "NextDocumentLib":
"""Create the component. """Create the component.
@ -69,21 +69,21 @@ class Html(NextDocumentLib):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Html": ) -> "Html":
"""Create the component. """Create the component.
@ -115,21 +115,21 @@ class DocumentHead(NextDocumentLib):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "DocumentHead": ) -> "DocumentHead":
"""Create the component. """Create the component.
@ -161,21 +161,21 @@ class Main(NextDocumentLib):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Main": ) -> "Main":
"""Create the component. """Create the component.
@ -207,21 +207,21 @@ class NextScript(NextDocumentLib):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "NextScript": ) -> "NextScript":
"""Create the component. """Create the component.

View File

@ -11,10 +11,11 @@ from reflex.event import EventHandler, set_clipboard
from reflex.state import FrontendEventExceptionState from reflex.state import FrontendEventExceptionState
from reflex.vars.base import Var from reflex.vars.base import Var
from reflex.vars.function import ArgsFunctionOperation from reflex.vars.function import ArgsFunctionOperation
from reflex.vars.object import ObjectVar
def on_error_spec( def on_error_spec(
error: Var[Dict[str, str]], info: Var[Dict[str, str]] error: ObjectVar[Dict[str, str]], info: ObjectVar[Dict[str, str]]
) -> Tuple[Var[str], Var[str]]: ) -> Tuple[Var[str], Var[str]]:
"""The spec for the on_error event handler. """The spec for the on_error event handler.

View File

@ -6,12 +6,13 @@
from typing import Any, Dict, Optional, Tuple, Union, overload from typing import Any, Dict, Optional, Tuple, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
from reflex.vars.object import ObjectVar
def on_error_spec( def on_error_spec(
error: Var[Dict[str, str]], info: Var[Dict[str, str]] error: ObjectVar[Dict[str, str]], info: ObjectVar[Dict[str, str]]
) -> Tuple[Var[str], Var[str]]: ... ) -> Tuple[Var[str], Var[str]]: ...
class ErrorBoundary(Component): class ErrorBoundary(Component):
@ -27,28 +28,24 @@ class ErrorBoundary(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_error: Optional[ on_error: Optional[
Union[ Union[EventType[()], EventType[str], EventType[str, str]]
EventType[[], BASE_STATE],
EventType[[str], BASE_STATE],
EventType[[str, str], BASE_STATE],
]
] = None, ] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ErrorBoundary": ) -> "ErrorBoundary":
"""Create an ErrorBoundary component. """Create an ErrorBoundary component.

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -22,21 +22,21 @@ class Fragment(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Fragment": ) -> "Fragment":
"""Create the component. """Create the component.

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.component import Component, MemoizationLeaf from reflex.components.component import Component, MemoizationLeaf
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -22,21 +22,21 @@ class NextHeadLib(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "NextHeadLib": ) -> "NextHeadLib":
"""Create the component. """Create the component.
@ -68,21 +68,21 @@ class Head(NextHeadLib, MemoizationLeaf):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Head": ) -> "Head":
"""Create a new memoization leaf component. """Create a new memoization leaf component.

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -24,21 +24,21 @@ class RawLink(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "RawLink": ) -> "RawLink":
"""Create the component. """Create the component.
@ -79,21 +79,21 @@ class ScriptTag(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ScriptTag": ) -> "ScriptTag":
"""Create the component. """Create the component.

View File

@ -53,11 +53,11 @@ class Description(Meta):
"""A component that displays the title of the current page.""" """A component that displays the title of the current page."""
# The type of the description. # The type of the description.
name: str = "description" name: str | None = "description"
class Image(Meta): class Image(Meta):
"""A component that displays the title of the current page.""" """A component that displays the title of the current page."""
# The type of the image. # The type of the image.
property: str = "og:image" property: str | None = "og:image"

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -23,21 +23,21 @@ class Title(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Title": ) -> "Title":
"""Create the component. """Create the component.
@ -74,21 +74,21 @@ class Meta(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Meta": ) -> "Meta":
"""Create the component. """Create the component.
@ -130,21 +130,21 @@ class Description(Meta):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Description": ) -> "Description":
"""Create the component. """Create the component.
@ -186,21 +186,21 @@ class Image(Meta):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Image": ) -> "Image":
"""Create the component. """Create the component.

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Literal, Optional, Union, overload from typing import Any, Dict, Literal, Optional, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -29,24 +29,24 @@ class Script(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_error: Optional[EventType[[], BASE_STATE]] = None, on_error: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_load: Optional[EventType[[], BASE_STATE]] = None, on_load: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_ready: Optional[EventType[[], BASE_STATE]] = None, on_ready: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Script": ) -> "Script":
"""Create an inline or user-defined script. """Create an inline or user-defined script.

View File

@ -0,0 +1,10 @@
"""Module for the StrictMode component."""
from reflex.components.component import Component
class StrictMode(Component):
"""A React strict mode component to enable strict mode for its children."""
library = "react"
tag = "StrictMode"

View File

@ -0,0 +1,57 @@
"""Stub file for reflex/components/base/strict_mode.py"""
# ------------------- DO NOT EDIT ----------------------
# This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------
from typing import Any, Dict, Optional, Union, overload
from reflex.components.component import Component
from reflex.event import EventType
from reflex.style import Style
from reflex.vars.base import Var
class StrictMode(Component):
@overload
@classmethod
def create( # type: ignore
cls,
*children,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[()]] = None,
**props,
) -> "StrictMode":
"""Create the component.
Args:
*children: The children of the component.
style: The style of the component.
key: A unique key for the component.
id: The id for the component.
class_name: The class name for the component.
autofocus: Whether the component should take the focus once the page is loaded
custom_attrs: custom attribute
**props: The props of the component.
Returns:
The component.
"""
...

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import copy import copy
import dataclasses import dataclasses
import inspect
import typing import typing
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from functools import lru_cache, wraps from functools import lru_cache, wraps
@ -21,9 +22,11 @@ from typing import (
Set, Set,
Type, Type,
Union, Union,
get_args,
get_origin,
) )
from typing_extensions import deprecated from typing_extensions import Self
import reflex.state import reflex.state
from reflex.base import Base from reflex.base import Base
@ -43,22 +46,16 @@ from reflex.constants import (
from reflex.constants.compiler import SpecialAttributes from reflex.constants.compiler import SpecialAttributes
from reflex.constants.state import FRONTEND_EVENT_STATE from reflex.constants.state import FRONTEND_EVENT_STATE
from reflex.event import ( from reflex.event import (
EventActionsMixin,
EventCallback, EventCallback,
EventChain, EventChain,
EventHandler, EventHandler,
EventSpec, EventSpec,
EventVar,
no_args_event_spec, no_args_event_spec,
) )
from reflex.style import Style, format_as_emotion from reflex.style import Style, format_as_emotion
from reflex.utils import console, format, imports, types from reflex.utils import format, imports, types
from reflex.utils.imports import ( from reflex.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_imports
ImmutableParsedImportDict,
ImportDict,
ImportVar,
ParsedImportDict,
parse_imports,
)
from reflex.vars import VarData from reflex.vars import VarData
from reflex.vars.base import ( from reflex.vars.base import (
CachedVarOperation, CachedVarOperation,
@ -153,7 +150,7 @@ class BaseComponent(Base, ABC):
class ComponentNamespace(SimpleNamespace): class ComponentNamespace(SimpleNamespace):
"""A namespace to manage components with subcomponents.""" """A namespace to manage components with subcomponents."""
def __hash__(self) -> int: def __hash__(self) -> int: # pyright: ignore [reportIncompatibleVariableOverride]
"""Get the hash of the namespace. """Get the hash of the namespace.
Returns: Returns:
@ -182,6 +179,7 @@ ComponentStyle = Dict[
Union[str, Type[BaseComponent], Callable, ComponentNamespace], Any Union[str, Type[BaseComponent], Callable, ComponentNamespace], Any
] ]
ComponentChild = Union[types.PrimitiveType, Var, BaseComponent] ComponentChild = Union[types.PrimitiveType, Var, BaseComponent]
ComponentChildTypes = (*types.PrimitiveTypes, Var, BaseComponent)
def satisfies_type_hint(obj: Any, type_hint: Any) -> bool: def satisfies_type_hint(obj: Any, type_hint: Any) -> bool:
@ -194,11 +192,26 @@ def satisfies_type_hint(obj: Any, type_hint: Any) -> bool:
Returns: Returns:
Whether the object satisfies the type hint. Whether the object satisfies the type hint.
""" """
if isinstance(obj, LiteralVar): return types._isinstance(obj, type_hint, nested=1)
return types._isinstance(obj._var_value, type_hint)
if isinstance(obj, Var):
return types._issubclass(obj._var_type, type_hint) def _components_from(
return types._isinstance(obj, type_hint) component_or_var: Union[BaseComponent, Var],
) -> tuple[BaseComponent, ...]:
"""Get the components from a component or Var.
Args:
component_or_var: The component or Var to get the components from.
Returns:
The components.
"""
if isinstance(component_or_var, Var):
var_data = component_or_var._get_all_var_data()
return var_data.components if var_data else ()
if isinstance(component_or_var, BaseComponent):
return (component_or_var,)
return ()
class Component(BaseComponent, ABC): class Component(BaseComponent, ABC):
@ -429,20 +442,22 @@ class Component(BaseComponent, ABC):
else: else:
continue continue
def determine_key(value: Any):
# Try to create a var from the value
key = value if isinstance(value, Var) else LiteralVar.create(value)
# Check that the var type is not None.
if key is None:
raise TypeError
return key
# Check whether the key is a component prop. # Check whether the key is a component prop.
if types._issubclass(field_type, Var): if types._issubclass(field_type, Var):
# Used to store the passed types if var type is a union. # Used to store the passed types if var type is a union.
passed_types = None passed_types = None
try: try:
# Try to create a var from the value. kwargs[key] = determine_key(value)
if isinstance(value, Var):
kwargs[key] = value
else:
kwargs[key] = LiteralVar.create(value)
# Check that the var type is not None.
if kwargs[key] is None:
raise TypeError
expected_type = fields[key].outer_type_.__args__[0] expected_type = fields[key].outer_type_.__args__[0]
# validate literal fields. # validate literal fields.
@ -463,9 +478,7 @@ class Component(BaseComponent, ABC):
if types.is_union(passed_type): if types.is_union(passed_type):
# We need to check all possible types in the union. # We need to check all possible types in the union.
passed_types = ( passed_types = (
arg arg for arg in passed_type.__args__ if arg is not type(None)
for arg in passed_type.__args__ # type: ignore
if arg is not type(None)
) )
if ( if (
# If the passed var is a union, check if all possible types are valid. # If the passed var is a union, check if all possible types are valid.
@ -492,14 +505,14 @@ class Component(BaseComponent, ABC):
# Check if the key is an event trigger. # Check if the key is an event trigger.
if key in component_specific_triggers: if key in component_specific_triggers:
kwargs["event_triggers"][key] = EventChain.create( kwargs["event_triggers"][key] = EventChain.create(
value=value, # type: ignore value=value,
args_spec=component_specific_triggers[key], args_spec=component_specific_triggers[key],
key=key, key=key,
) )
# Remove any keys that were added as events. # Remove any keys that were added as events.
for key in kwargs["event_triggers"]: for key in kwargs["event_triggers"]:
del kwargs[key] kwargs.pop(key, None)
# Place data_ and aria_ attributes into custom_attrs # Place data_ and aria_ attributes into custom_attrs
special_attributes = tuple( special_attributes = tuple(
@ -545,41 +558,6 @@ class Component(BaseComponent, ABC):
# Construct the component. # Construct the component.
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@deprecated("Use rx.EventChain.create instead.")
def _create_event_chain(
self,
args_spec: types.ArgsSpec | Sequence[types.ArgsSpec],
value: Union[
Var,
EventHandler,
EventSpec,
List[Union[EventHandler, EventSpec, EventVar]],
Callable,
],
key: Optional[str] = None,
) -> Union[EventChain, Var]:
"""Create an event chain from a variety of input types.
Args:
args_spec: The args_spec of the event trigger being bound.
value: The value to create the event chain from.
key: The key of the event trigger being bound.
Returns:
The event chain.
"""
console.deprecate(
"Component._create_event_chain",
"Use rx.EventChain.create instead.",
deprecation_version="0.6.8",
removal_version="0.7.0",
)
return EventChain.create(
value=value, # type: ignore
args_spec=args_spec,
key=key,
)
def get_event_triggers( def get_event_triggers(
self, self,
) -> Dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]: ) -> Dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]:
@ -614,7 +592,7 @@ class Component(BaseComponent, ABC):
annotation = field.annotation annotation = field.annotation
if (metadata := getattr(annotation, "__metadata__", None)) is not None: if (metadata := getattr(annotation, "__metadata__", None)) is not None:
args_spec = metadata[0] args_spec = metadata[0]
default_triggers[field.name] = args_spec or (no_args_event_spec) # type: ignore default_triggers[field.name] = args_spec or (no_args_event_spec)
return default_triggers return default_triggers
def __repr__(self) -> str: def __repr__(self) -> str:
@ -661,8 +639,7 @@ class Component(BaseComponent, ABC):
if props is None: if props is None:
# Add component props to the tag. # Add component props to the tag.
props = { props = {
attr[:-1] if attr.endswith("_") else attr: getattr(self, attr) attr.removesuffix("_"): getattr(self, attr) for attr in self.get_props()
for attr in self.get_props()
} }
# Add ref to element if `id` is not None. # Add ref to element if `id` is not None.
@ -712,12 +689,21 @@ class Component(BaseComponent, ABC):
return set() return set()
@classmethod @classmethod
@lru_cache(maxsize=None) def _are_fields_known(cls) -> bool:
def get_component_props(cls) -> set[str]: """Check if all fields are known at compile time. True for most components.
"""Get the props that expected a component as value.
Returns: Returns:
The components props. Whether all fields are known at compile time.
"""
return True
@classmethod
@lru_cache(maxsize=None)
def _get_component_prop_names(cls) -> Set[str]:
"""Get the names of the component props. NOTE: This assumes all fields are known.
Returns:
The names of the component props.
""" """
return { return {
name name
@ -726,8 +712,28 @@ class Component(BaseComponent, ABC):
and types._issubclass(field.outer_type_, Component) and types._issubclass(field.outer_type_, Component)
} }
def _get_components_in_props(self) -> Sequence[BaseComponent]:
"""Get the components in the props.
Returns:
The components in the props
"""
if self._are_fields_known():
return [
component
for name in self._get_component_prop_names()
for component in _components_from(getattr(self, name))
]
return [
component
for prop in self.get_props()
if (value := getattr(self, prop)) is not None
and isinstance(value, (BaseComponent, Var))
for component in _components_from(value)
]
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children, **props) -> Self:
"""Create the component. """Create the component.
Args: Args:
@ -740,22 +746,21 @@ class Component(BaseComponent, ABC):
# Import here to avoid circular imports. # Import here to avoid circular imports.
from reflex.components.base.bare import Bare from reflex.components.base.bare import Bare
from reflex.components.base.fragment import Fragment from reflex.components.base.fragment import Fragment
from reflex.utils.exceptions import ComponentTypeError from reflex.utils.exceptions import ChildrenTypeError
# Filter out None props # Filter out None props
props = {key: value for key, value in props.items() if value is not None} props = {key: value for key, value in props.items() if value is not None}
def validate_children(children): def validate_children(children: tuple | list):
for child in children: for child in children:
if isinstance(child, tuple): if isinstance(child, (tuple, list)):
validate_children(child) validate_children(child)
# Make sure the child is a valid type. # Make sure the child is a valid type.
if not types._isinstance(child, ComponentChild): if isinstance(child, dict) or not isinstance(
raise ComponentTypeError( child, ComponentChildTypes
"Children of Reflex components must be other components, " ):
"state vars, or primitive Python types. " raise ChildrenTypeError(component=cls.__name__, child=child)
f"Got child {child} of type {type(child)}.",
)
# Validate all the children. # Validate all the children.
validate_children(children) validate_children(children)
@ -798,7 +803,7 @@ class Component(BaseComponent, ABC):
# Walk the MRO to call all `add_style` methods. # Walk the MRO to call all `add_style` methods.
for base in self._iter_parent_classes_with_method("add_style"): for base in self._iter_parent_classes_with_method("add_style"):
s = base.add_style(self) # type: ignore s = base.add_style(self)
if s is not None: if s is not None:
styles.append(s) styles.append(s)
@ -890,7 +895,7 @@ class Component(BaseComponent, ABC):
else {} else {}
) )
def render(self) -> Dict: def render(self) -> dict:
"""Render the component. """Render the component.
Returns: Returns:
@ -908,7 +913,7 @@ class Component(BaseComponent, ABC):
self._replace_prop_names(rendered_dict) self._replace_prop_names(rendered_dict)
return rendered_dict return rendered_dict
def _replace_prop_names(self, rendered_dict) -> None: def _replace_prop_names(self, rendered_dict: dict) -> None:
"""Replace the prop names in the render dictionary. """Replace the prop names in the render dictionary.
Args: Args:
@ -948,7 +953,7 @@ class Component(BaseComponent, ABC):
comp.__name__ for comp in (Fragment, Foreach, Cond, Match) comp.__name__ for comp in (Fragment, Foreach, Cond, Match)
] ]
def validate_child(child): def validate_child(child: Any):
child_name = type(child).__name__ child_name = type(child).__name__
# Iterate through the immediate children of fragment # Iterate through the immediate children of fragment
@ -1183,6 +1188,9 @@ class Component(BaseComponent, ABC):
if custom_code is not None: if custom_code is not None:
code.add(custom_code) code.add(custom_code)
for component in self._get_components_in_props():
code |= component._get_all_custom_code()
# Add the custom code from add_custom_code method. # Add the custom code from add_custom_code method.
for clz in self._iter_parent_classes_with_method("add_custom_code"): for clz in self._iter_parent_classes_with_method("add_custom_code"):
for item in clz.add_custom_code(self): for item in clz.add_custom_code(self):
@ -1210,7 +1218,7 @@ class Component(BaseComponent, ABC):
The dynamic imports. The dynamic imports.
""" """
# Store the import in a set to avoid duplicates. # Store the import in a set to avoid duplicates.
dynamic_imports = set() dynamic_imports: set[str] = set()
# Get dynamic import for this component. # Get dynamic import for this component.
dynamic_import = self._get_dynamic_imports() dynamic_import = self._get_dynamic_imports()
@ -1221,25 +1229,12 @@ class Component(BaseComponent, ABC):
for child in self.children: for child in self.children:
dynamic_imports |= child._get_all_dynamic_imports() dynamic_imports |= child._get_all_dynamic_imports()
for prop in self.get_component_props(): for component in self._get_components_in_props():
if getattr(self, prop) is not None: dynamic_imports |= component._get_all_dynamic_imports()
dynamic_imports |= getattr(self, prop)._get_all_dynamic_imports()
# Return the dynamic imports # Return the dynamic imports
return dynamic_imports return dynamic_imports
def _get_props_imports(self) -> List[ParsedImportDict]:
"""Get the imports needed for components props.
Returns:
The imports for the components props of the component.
"""
return [
getattr(self, prop)._get_all_imports()
for prop in self.get_component_props()
if getattr(self, prop) is not None
]
def _should_transpile(self, dep: str | None) -> bool: def _should_transpile(self, dep: str | None) -> bool:
"""Check if a dependency should be transpiled. """Check if a dependency should be transpiled.
@ -1249,7 +1244,7 @@ class Component(BaseComponent, ABC):
Returns: Returns:
True if the dependency should be transpiled. True if the dependency should be transpiled.
""" """
return ( return bool(self.transpile_packages) and (
dep in self.transpile_packages dep in self.transpile_packages
or format.format_library_name(dep or "") in self.transpile_packages or format.format_library_name(dep or "") in self.transpile_packages
) )
@ -1332,9 +1327,10 @@ class Component(BaseComponent, ABC):
event_imports = Imports.EVENTS if self.event_triggers else {} event_imports = Imports.EVENTS if self.event_triggers else {}
# Collect imports from Vars used directly by this component. # Collect imports from Vars used directly by this component.
var_datas = [var._get_all_var_data() for var in self._get_vars()] var_imports = [
var_imports: List[ImmutableParsedImportDict] = [ var_data.imports
var_data.imports for var_data in var_datas if var_data is not None for var in self._get_vars()
if (var_data := var._get_all_var_data()) is not None
] ]
added_import_dicts: list[ParsedImportDict] = [] added_import_dicts: list[ParsedImportDict] = []
@ -1349,7 +1345,6 @@ class Component(BaseComponent, ABC):
) )
return imports.merge_imports( return imports.merge_imports(
*self._get_props_imports(),
self._get_dependencies_imports(), self._get_dependencies_imports(),
self._get_hooks_imports(), self._get_hooks_imports(),
_imports, _imports,
@ -1426,6 +1421,8 @@ class Component(BaseComponent, ABC):
for k in var_data.hooks for k in var_data.hooks
} }
) )
for component in var_data.components:
vars_hooks.update(component._get_all_hooks())
return vars_hooks return vars_hooks
def _get_events_hooks(self) -> dict[str, VarData | None]: def _get_events_hooks(self) -> dict[str, VarData | None]:
@ -1574,6 +1571,9 @@ class Component(BaseComponent, ABC):
refs.add(ref) refs.add(ref)
for child in self.children: for child in self.children:
refs |= child._get_all_refs() refs |= child._get_all_refs()
for component in self._get_components_in_props():
refs |= component._get_all_refs()
return refs return refs
def _get_all_custom_components( def _get_all_custom_components(
@ -1597,6 +1597,9 @@ class Component(BaseComponent, ABC):
if not isinstance(child, Component): if not isinstance(child, Component):
continue continue
custom_components |= child._get_all_custom_components(seen=seen) custom_components |= child._get_all_custom_components(seen=seen)
for component in self._get_components_in_props():
if isinstance(component, Component) and component.tag is not None:
custom_components |= component._get_all_custom_components(seen=seen)
return custom_components return custom_components
@property @property
@ -1660,17 +1663,65 @@ class CustomComponent(Component):
# The props of the component. # The props of the component.
props: Dict[str, Any] = {} props: Dict[str, Any] = {}
# Props that reference other components. def __init__(self, **kwargs):
component_props: Dict[str, Component] = {}
def __init__(self, *args, **kwargs):
"""Initialize the custom component. """Initialize the custom component.
Args: Args:
*args: The args to pass to the component.
**kwargs: The kwargs to pass to the component. **kwargs: The kwargs to pass to the component.
""" """
super().__init__(*args, **kwargs) component_fn = kwargs.get("component_fn")
# Set the props.
props_types = typing.get_type_hints(component_fn) if component_fn else {}
props = {key: value for key, value in kwargs.items() if key in props_types}
kwargs = {key: value for key, value in kwargs.items() if key not in props_types}
event_types = {
key
for key in props
if (
(get_origin((annotation := props_types.get(key))) or annotation)
== EventHandler
)
}
def get_args_spec(key: str) -> types.ArgsSpec | Sequence[types.ArgsSpec]:
type_ = props_types[key]
return (
args[0]
if (args := get_args(type_))
else (
annotation_args[1]
if get_origin(
(
annotation := inspect.getfullargspec(
component_fn
).annotations[key]
)
)
is typing.Annotated
and (annotation_args := get_args(annotation))
else no_args_event_spec
)
)
super().__init__(
event_triggers={
key: EventChain.create(
value=props[key],
args_spec=get_args_spec(key),
key=key,
)
for key in event_types
},
**kwargs,
)
to_camel_cased_props = {
format.to_camel_case(key) for key in props if key not in event_types
}
self.get_props = lambda: to_camel_cased_props # pyright: ignore [reportIncompatibleVariableOverride]
# Unset the style. # Unset the style.
self.style = Style() self.style = Style()
@ -1678,51 +1729,36 @@ class CustomComponent(Component):
# Set the tag to the name of the function. # Set the tag to the name of the function.
self.tag = format.to_title_case(self.component_fn.__name__) self.tag = format.to_title_case(self.component_fn.__name__)
# Get the event triggers defined in the component declaration. for key, value in props.items():
event_triggers_in_component_declaration = self.get_event_triggers()
# Set the props.
props = typing.get_type_hints(self.component_fn)
for key, value in kwargs.items():
# Skip kwargs that are not props. # Skip kwargs that are not props.
if key not in props: if key not in props_types:
continue continue
camel_cased_key = format.to_camel_case(key)
# Get the type based on the annotation. # Get the type based on the annotation.
type_ = props[key] type_ = props_types[key]
# Handle event chains. # Handle event chains.
if types._issubclass(type_, EventChain): if types._issubclass(type_, EventActionsMixin):
value = EventChain.create( inspect.getfullargspec(component_fn).annotations[key]
value=value, self.props[camel_cased_key] = EventChain.create(
args_spec=event_triggers_in_component_declaration.get( value=value, args_spec=get_args_spec(key), key=key
key, no_args_event_spec
),
key=key,
) )
self.props[format.to_camel_case(key)] = value
continue continue
# Handle subclasses of Base. value = LiteralVar.create(value)
if isinstance(value, Base): self.props[camel_cased_key] = value
base_value = LiteralVar.create(value) setattr(self, camel_cased_key, value)
# Track hooks and imports associated with Component instances. @classmethod
if base_value is not None and isinstance(value, Component): def _are_fields_known(cls) -> bool:
self.component_props[key] = value """Check if the fields are known.
value = base_value._replace(
merge_var_data=VarData( # type: ignore
imports=value._get_all_imports(),
hooks=value._get_all_hooks(),
)
)
else:
value = base_value
else:
value = LiteralVar.create(value)
# Set the prop. Returns:
self.props[format.to_camel_case(key)] = value Whether the fields are known.
"""
return False
def __eq__(self, other: Any) -> bool: def __eq__(self, other: Any) -> bool:
"""Check if the component is equal to another. """Check if the component is equal to another.
@ -1781,27 +1817,8 @@ class CustomComponent(Component):
seen=seen seen=seen
) )
# Fetch custom components from props as well.
for child_component in self.component_props.values():
if child_component.tag is None:
continue
if child_component.tag not in seen:
seen.add(child_component.tag)
if isinstance(child_component, CustomComponent):
custom_components |= {child_component}
custom_components |= child_component._get_all_custom_components(
seen=seen
)
return custom_components return custom_components
def _render(self) -> Tag:
"""Define how to render the component in React.
Returns:
The tag to render.
"""
return super()._render(props=self.props)
def get_prop_vars(self) -> List[Var]: def get_prop_vars(self) -> List[Var]:
"""Get the prop vars. """Get the prop vars.
@ -1812,34 +1829,19 @@ class CustomComponent(Component):
Var( Var(
_js_expr=name, _js_expr=name,
_var_type=( _var_type=(
prop._var_type if types._isinstance(prop, Var) else type(prop) prop._var_type
if isinstance(prop, Var)
else (
type(prop)
if not isinstance(prop, EventActionsMixin)
else EventChain
)
), ),
).guess_type() ).guess_type()
for name, prop in self.props.items() for name, prop in self.props.items()
] ]
def _get_vars( @lru_cache(maxsize=None) # noqa: B019
self, include_children: bool = False, ignore_ids: set[int] | None = None
) -> Iterator[Var]:
"""Walk all Vars used in this component.
Args:
include_children: Whether to include Vars from children.
ignore_ids: The ids to ignore.
Yields:
Each var referenced by the component (props, styles, event handlers).
"""
ignore_ids = ignore_ids or set()
yield from super()._get_vars(
include_children=include_children, ignore_ids=ignore_ids
)
yield from filter(lambda prop: isinstance(prop, Var), self.props.values())
yield from self.get_component(self)._get_vars(
include_children=include_children, ignore_ids=ignore_ids
)
@lru_cache(maxsize=None) # noqa
def get_component(self) -> Component: def get_component(self) -> Component:
"""Render the component. """Render the component.
@ -1983,7 +1985,7 @@ class StatefulComponent(BaseComponent):
if not should_memoize: if not should_memoize:
# Determine if any Vars have associated data. # Determine if any Vars have associated data.
for prop_var in component._get_vars(): for prop_var in component._get_vars(include_children=True):
if prop_var._get_all_var_data(): if prop_var._get_all_var_data():
should_memoize = True should_memoize = True
break break
@ -2366,8 +2368,8 @@ class MemoizationLeaf(Component):
""" """
comp = super().create(*children, **props) comp = super().create(*children, **props)
if comp._get_all_hooks(): if comp._get_all_hooks():
comp._memoization_mode = cls._memoization_mode.copy( comp._memoization_mode = dataclasses.replace(
update={"disposition": MemoizationDisposition.ALWAYS} comp._memoization_mode, disposition=MemoizationDisposition.ALWAYS
) )
return comp return comp
@ -2428,7 +2430,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
if tag["name"] == "match": if tag["name"] == "match":
element = tag["cond"] element = tag["cond"]
conditionals = tag["default"] conditionals = render_dict_to_var(tag["default"], imported_names)
for case in tag["match_cases"][::-1]: for case in tag["match_cases"][::-1]:
condition = case[0].to_string() == element.to_string() condition = case[0].to_string() == element.to_string()
@ -2437,7 +2439,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
conditionals = ternary_operation( conditionals = ternary_operation(
condition, condition,
case[-1], render_dict_to_var(case[-1], imported_names),
conditionals, conditionals,
) )
@ -2496,6 +2498,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
@dataclasses.dataclass( @dataclasses.dataclass(
eq=False, eq=False,
frozen=True, frozen=True,
slots=True,
) )
class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar): class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
"""A Var that represents a Component.""" """A Var that represents a Component."""
@ -2525,6 +2528,7 @@ class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
The VarData for the var. The VarData for the var.
""" """
return VarData.merge( return VarData.merge(
self._var_data,
VarData( VarData(
imports={ imports={
"@emotion/react": [ "@emotion/react": [
@ -2567,9 +2571,21 @@ class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
Returns: Returns:
The var. The var.
""" """
var_datas = [
var_data
for var in value._get_vars(include_children=True)
if (var_data := var._get_all_var_data())
]
return LiteralComponentVar( return LiteralComponentVar(
_js_expr="", _js_expr="",
_var_type=type(value), _var_type=type(value),
_var_data=_var_data, _var_data=VarData.merge(
_var_data,
*var_datas,
VarData(
components=(value,),
),
),
_var_value=value, _var_value=value,
) )

View File

@ -48,6 +48,7 @@ _SUBMOD_ATTRS: dict[str, list[str]] = {
"get_upload_url", "get_upload_url",
"selected_files", "selected_files",
], ],
"auto_scroll": ["auto_scroll"],
} }
__getattr__, __dir__, __all__ = lazy_loader.attach( __getattr__, __dir__, __all__ = lazy_loader.attach(

View File

@ -4,6 +4,7 @@
# ------------------------------------------------------ # ------------------------------------------------------
from . import layout as layout from . import layout as layout
from .auto_scroll import auto_scroll as auto_scroll
from .banner import ConnectionBanner as ConnectionBanner from .banner import ConnectionBanner as ConnectionBanner
from .banner import ConnectionModal as ConnectionModal from .banner import ConnectionModal as ConnectionModal
from .banner import ConnectionPulser as ConnectionPulser from .banner import ConnectionPulser as ConnectionPulser

View File

@ -0,0 +1,111 @@
"""A component that automatically scrolls to the bottom when new content is added."""
from __future__ import annotations
from reflex.components.el.elements.typography import Div
from reflex.constants.compiler import MemoizationDisposition, MemoizationMode
from reflex.utils.imports import ImportDict
from reflex.vars.base import Var, get_unique_variable_name
class AutoScroll(Div):
"""A div that automatically scrolls to the bottom when new content is added."""
_memoization_mode = MemoizationMode(disposition=MemoizationDisposition.ALWAYS)
@classmethod
def create(cls, *children, **props):
"""Create an AutoScroll component.
Args:
*children: The children of the component.
**props: The props of the component.
Returns:
An AutoScroll component.
"""
props.setdefault("overflow", "auto")
props.setdefault("id", get_unique_variable_name())
return super().create(*children, **props)
def add_imports(self) -> ImportDict | list[ImportDict]:
"""Add imports required for the component.
Returns:
The imports required for the component.
"""
return {"react": ["useEffect", "useRef"]}
def add_hooks(self) -> list[str | Var]:
"""Add hooks required for the component.
Returns:
The hooks required for the component.
"""
ref_name = self.get_ref()
return [
"const containerRef = useRef(null);",
"const wasNearBottom = useRef(false);",
"const hadScrollbar = useRef(false);",
f"""
const checkIfNearBottom = () => {{
if (!{ref_name}.current) return;
const container = {ref_name}.current;
const nearBottomThreshold = 50; // pixels from bottom to trigger auto-scroll
const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
wasNearBottom.current = distanceFromBottom <= nearBottomThreshold;
// Track if container had a scrollbar
hadScrollbar.current = container.scrollHeight > container.clientHeight;
}};
""",
f"""
const scrollToBottomIfNeeded = () => {{
if (!{ref_name}.current) return;
const container = {ref_name}.current;
const hasScrollbarNow = container.scrollHeight > container.clientHeight;
// Scroll if:
// 1. User was near bottom, OR
// 2. Container didn't have scrollbar before but does now
if (wasNearBottom.current || (!hadScrollbar.current && hasScrollbarNow)) {{
container.scrollTop = container.scrollHeight;
}}
// Update scrollbar state for next check
hadScrollbar.current = hasScrollbarNow;
}};
""",
f"""
useEffect(() => {{
const container = {ref_name}.current;
if (!container) return;
// Create ResizeObserver to detect height changes
const resizeObserver = new ResizeObserver(() => {{
scrollToBottomIfNeeded();
}});
// Track scroll position before height changes
container.addEventListener('scroll', checkIfNearBottom);
// Initial check
checkIfNearBottom();
// Observe container for size changes
resizeObserver.observe(container);
return () => {{
container.removeEventListener('scroll', checkIfNearBottom);
resizeObserver.disconnect();
}};
}});
""",
]
auto_scroll = AutoScroll.create

View File

@ -0,0 +1,284 @@
"""Stub file for reflex/components/core/auto_scroll.py"""
# ------------------- DO NOT EDIT ----------------------
# This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------
from typing import Any, Dict, Literal, Optional, Union, overload
from reflex.components.el.elements.typography import Div
from reflex.event import EventType
from reflex.style import Style
from reflex.utils.imports import ImportDict
from reflex.vars.base import Var
class AutoScroll(Div):
@overload
@classmethod
def create( # type: ignore
cls,
*children,
access_key: Optional[Union[Var[str], str]] = None,
auto_capitalize: Optional[
Union[
Literal["characters", "none", "off", "on", "sentences", "words"],
Var[Literal["characters", "none", "off", "on", "sentences", "words"]],
]
] = None,
content_editable: Optional[
Union[
Literal["inherit", "plaintext-only", False, True],
Var[Literal["inherit", "plaintext-only", False, True]],
]
] = None,
context_menu: Optional[Union[Var[str], str]] = None,
dir: Optional[Union[Var[str], str]] = None,
draggable: Optional[Union[Var[bool], bool]] = None,
enter_key_hint: Optional[
Union[
Literal["done", "enter", "go", "next", "previous", "search", "send"],
Var[
Literal["done", "enter", "go", "next", "previous", "search", "send"]
],
]
] = None,
hidden: Optional[Union[Var[bool], bool]] = None,
input_mode: Optional[
Union[
Literal[
"decimal",
"email",
"none",
"numeric",
"search",
"tel",
"text",
"url",
],
Var[
Literal[
"decimal",
"email",
"none",
"numeric",
"search",
"tel",
"text",
"url",
]
],
]
] = None,
item_prop: Optional[Union[Var[str], str]] = None,
lang: Optional[Union[Var[str], str]] = None,
role: Optional[
Union[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
],
Var[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
]
],
]
] = None,
slot: Optional[Union[Var[str], str]] = None,
spell_check: Optional[Union[Var[bool], bool]] = None,
tab_index: Optional[Union[Var[int], int]] = None,
title: Optional[Union[Var[str], str]] = None,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[()]] = None,
**props,
) -> "AutoScroll":
"""Create an AutoScroll component.
Args:
*children: The children of the component.
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.
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
draggable: Defines whether the element can be dragged.
enter_key_hint: Hints what media types the media element is able to play.
hidden: Defines whether the element is hidden.
input_mode: Defines the type of the element.
item_prop: Defines the name of the element for metadata purposes.
lang: Defines the language used in the element.
role: Defines the role of the element.
slot: Assigns a slot in a shadow DOM shadow tree to an element.
spell_check: Defines whether the element may be checked for spelling errors.
tab_index: Defines the position of the current element in the tabbing order.
title: Defines a tooltip for the element.
style: The style of the component.
key: A unique key for the component.
id: The id for the component.
class_name: The class name for the component.
autofocus: Whether the component should take the focus once the page is loaded
custom_attrs: custom attribute
**props: The props of the component.
Returns:
An AutoScroll component.
"""
...
def add_imports(self) -> ImportDict | list[ImportDict]: ...
def add_hooks(self) -> list[str | Var]: ...
auto_scroll = AutoScroll.create

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from typing import Optional from typing import Optional
from reflex import constants
from reflex.components.component import Component from reflex.components.component import Component
from reflex.components.core.cond import cond from reflex.components.core.cond import cond
from reflex.components.el.elements.typography import Div from reflex.components.el.elements.typography import Div
@ -16,6 +17,7 @@ from reflex.components.radix.themes.components.dialog import (
from reflex.components.radix.themes.layout.flex import Flex from reflex.components.radix.themes.layout.flex import Flex
from reflex.components.radix.themes.typography.text import Text from reflex.components.radix.themes.typography.text import Text
from reflex.components.sonner.toast import Toaster, ToastProps from reflex.components.sonner.toast import Toaster, ToastProps
from reflex.config import environment
from reflex.constants import Dirs, Hooks, Imports from reflex.constants import Dirs, Hooks, Imports
from reflex.constants.compiler import CompileVars from reflex.constants.compiler import CompileVars
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
@ -25,7 +27,7 @@ from reflex.vars.function import FunctionStringVar
from reflex.vars.number import BooleanVar from reflex.vars.number import BooleanVar
from reflex.vars.sequence import LiteralArrayVar from reflex.vars.sequence import LiteralArrayVar
connect_error_var_data: VarData = VarData( # type: ignore connect_error_var_data: VarData = VarData(
imports=Imports.EVENTS, imports=Imports.EVENTS,
hooks={Hooks.EVENTS: None}, hooks={Hooks.EVENTS: None},
) )
@ -99,24 +101,56 @@ class ConnectionToaster(Toaster):
""" """
toast_id = "websocket-error" toast_id = "websocket-error"
target_url = WebsocketTargetURL.create() target_url = WebsocketTargetURL.create()
props = ToastProps( # type: ignore props = ToastProps(
description=LiteralVar.create( description=LiteralVar.create(
f"Check if server is reachable at {target_url}", f"Check if server is reachable at {target_url}",
), ),
close_button=True, close_button=True,
duration=120000, duration=120000,
id=toast_id, id=toast_id,
) ) # pyright: ignore [reportCallIssue]
if environment.REFLEX_DOES_BACKEND_COLD_START.get():
loading_message = Var.create("Backend is starting.")
backend_is_loading_toast_var = Var(
f"toast.loading({loading_message!s}, {{...toast_props, description: '', closeButton: false, onDismiss: () => setUserDismissed(true)}},)"
)
backend_is_not_responding = Var.create("Backend is not responding.")
backend_is_down_toast_var = Var(
f"toast.error({backend_is_not_responding!s}, {{...toast_props, description: '', onDismiss: () => setUserDismissed(true)}},)"
)
toast_var = Var(
f"""
if (waitedForBackend) {{
{backend_is_down_toast_var!s}
}} else {{
{backend_is_loading_toast_var!s};
}}
setTimeout(() => {{
if ({has_too_many_connection_errors!s}) {{
setWaitedForBackend(true);
}}
}}, {environment.REFLEX_BACKEND_COLD_START_TIMEOUT.get() * 1000});
"""
)
else:
loading_message = Var.create(
f"Cannot connect to server: {connection_error}."
)
toast_var = Var(
f"toast.error({loading_message!s}, {{...toast_props, onDismiss: () => setUserDismissed(true)}},)"
)
individual_hooks = [ individual_hooks = [
f"const toast_props = {LiteralVar.create(props)!s};", f"const toast_props = {LiteralVar.create(props)!s};",
"const [userDismissed, setUserDismissed] = useState(false);", "const [userDismissed, setUserDismissed] = useState(false);",
"const [waitedForBackend, setWaitedForBackend] = useState(false);",
FunctionStringVar( FunctionStringVar(
"useEffect", "useEffect",
_var_data=VarData( _var_data=VarData(
imports={ imports={
"react": ["useEffect", "useState"], "react": ["useEffect", "useState"],
**dict(target_url._get_all_var_data().imports), # type: ignore **dict(target_url._get_all_var_data().imports), # pyright: ignore [reportArgumentType, reportOptionalMemberAccess]
} }
), ),
).call( ).call(
@ -126,10 +160,7 @@ class ConnectionToaster(Toaster):
() => {{ () => {{
if ({has_too_many_connection_errors!s}) {{ if ({has_too_many_connection_errors!s}) {{
if (!userDismissed) {{ if (!userDismissed) {{
toast.error( {toast_var!s}
`Cannot connect to server: ${{{connection_error}}}.`,
{{...toast_props, onDismiss: () => setUserDismissed(true)}},
)
}} }}
}} else {{ }} else {{
toast.dismiss("{toast_id}"); toast.dismiss("{toast_id}");
@ -138,7 +169,7 @@ class ConnectionToaster(Toaster):
}} }}
""" """
), ),
LiteralArrayVar.create([connect_errors]), LiteralArrayVar.create([connect_errors, Var("waitedForBackend")]),
), ),
] ]
@ -293,7 +324,161 @@ class ConnectionPulser(Div):
) )
class BackendDisabled(Div):
"""A component that displays a message when the backend is disabled."""
@classmethod
def create(cls, **props) -> Component:
"""Create a backend disabled component.
Args:
**props: The properties of the component.
Returns:
The backend disabled component.
"""
import reflex as rx
is_backend_disabled = Var(
"backendDisabled",
_var_type=bool,
_var_data=VarData(
hooks={
"const [backendDisabled, setBackendDisabled] = useState(false);": None,
"useEffect(() => { setBackendDisabled(isBackendDisabled()); }, []);": None,
},
imports={
f"$/{constants.Dirs.STATE_PATH}": [
ImportVar(tag="isBackendDisabled")
],
},
),
)
return super().create(
rx.cond(
is_backend_disabled,
rx.box(
rx.el.link(
rel="preconnect",
href="https://fonts.googleapis.com",
),
rx.el.link(
rel="preconnect",
href="https://fonts.gstatic.com",
crossorigin="",
),
rx.el.link(
href="https://fonts.googleapis.com/css2?family=Instrument+Sans:ital,wght@0,500;0,600&display=swap",
rel="stylesheet",
),
rx.box(
rx.vstack(
rx.text(
"This app is paused",
font_size="1.5rem",
font_weight="600",
line_height="1.25rem",
letter_spacing="-0.0375rem",
),
rx.hstack(
rx.el.svg(
rx.el.svg.path(
d="M6.90816 1.34341C7.61776 1.10786 8.38256 1.10786 9.09216 1.34341C9.7989 1.57799 10.3538 2.13435 10.9112 2.91605C11.4668 3.69515 12.0807 4.78145 12.872 6.18175L12.9031 6.23672C13.6946 7.63721 14.3085 8.72348 14.6911 9.60441C15.0755 10.4896 15.267 11.2539 15.1142 11.9881C14.9604 12.7275 14.5811 13.3997 14.0287 13.9079C13.4776 14.4147 12.7273 14.6286 11.7826 14.7313C10.8432 14.8334 9.6143 14.8334 8.0327 14.8334H7.9677C6.38604 14.8334 5.15719 14.8334 4.21778 14.7313C3.27301 14.6286 2.52269 14.4147 1.97164 13.9079C1.41924 13.3997 1.03995 12.7275 0.88613 11.9881C0.733363 11.2539 0.92483 10.4896 1.30926 9.60441C1.69184 8.72348 2.30573 7.63721 3.09722 6.23671L3.12828 6.18175C3.91964 4.78146 4.53355 3.69515 5.08914 2.91605C5.64658 2.13435 6.20146 1.57799 6.90816 1.34341ZM7.3335 11.3334C7.3335 10.9652 7.63063 10.6667 7.99716 10.6667H8.00316C8.3697 10.6667 8.66683 10.9652 8.66683 11.3334C8.66683 11.7016 8.3697 12.0001 8.00316 12.0001H7.99716C7.63063 12.0001 7.3335 11.7016 7.3335 11.3334ZM7.3335 8.66675C7.3335 9.03495 7.63196 9.33341 8.00016 9.33341C8.36836 9.33341 8.66683 9.03495 8.66683 8.66675V6.00008C8.66683 5.63189 8.36836 5.33341 8.00016 5.33341C7.63196 5.33341 7.3335 5.63189 7.3335 6.00008V8.66675Z",
fill_rule="evenodd",
clip_rule="evenodd",
fill=rx.color("amber", 11),
),
width="16",
height="16",
viewBox="0 0 16 16",
fill="none",
xmlns="http://www.w3.org/2000/svg",
margin_top="0.125rem",
flex_shrink="0",
),
rx.text(
"If you are the owner of this app, visit ",
rx.link(
"Reflex Cloud",
color=rx.color("amber", 11),
underline="always",
_hover={
"color": rx.color("amber", 11),
"text_decoration_color": rx.color(
"amber", 11
),
},
text_decoration_color=rx.color("amber", 10),
href="https://cloud.reflex.dev/",
font_weight="600",
is_external=True,
),
" for more information on how to resume your app.",
font_size="0.875rem",
font_weight="500",
line_height="1.25rem",
letter_spacing="-0.01094rem",
color=rx.color("amber", 11),
),
align="start",
gap="0.625rem",
border_radius="0.75rem",
border_width="1px",
border_color=rx.color("amber", 5),
background_color=rx.color("amber", 3),
padding="0.625rem",
),
rx.link(
rx.el.button(
"Resume app",
color="rgba(252, 252, 253, 1)",
font_size="0.875rem",
font_weight="600",
line_height="1.25rem",
letter_spacing="-0.01094rem",
height="2.5rem",
padding="0rem 0.75rem",
width="100%",
border_radius="0.75rem",
background=f"linear-gradient(180deg, {rx.color('violet', 9)} 0%, {rx.color('violet', 10)} 100%)",
_hover={
"background": f"linear-gradient(180deg, {rx.color('violet', 10)} 0%, {rx.color('violet', 10)} 100%)",
},
),
width="100%",
underline="none",
href="https://cloud.reflex.dev/",
is_external=True,
),
gap="1rem",
),
font_family='"Instrument Sans", "Helvetica", "Arial", sans-serif',
position="fixed",
top="50%",
left="50%",
transform="translate(-50%, -50%)",
width="60ch",
max_width="90vw",
border_radius="0.75rem",
border_width="1px",
border_color=rx.color("slate", 4),
padding="1.5rem",
background_color=rx.color("slate", 1),
box_shadow="0px 2px 5px 0px light-dark(rgba(28, 32, 36, 0.03), rgba(0, 0, 0, 0.00))",
),
position="fixed",
z_index=9999,
backdrop_filter="grayscale(1) blur(5px)",
width="100dvw",
height="100dvh",
),
)
)
connection_banner = ConnectionBanner.create connection_banner = ConnectionBanner.create
connection_modal = ConnectionModal.create connection_modal = ConnectionModal.create
connection_toaster = ConnectionToaster.create connection_toaster = ConnectionToaster.create
connection_pulser = ConnectionPulser.create connection_pulser = ConnectionPulser.create
backend_disabled = BackendDisabled.create

View File

@ -10,7 +10,7 @@ from reflex.components.el.elements.typography import Div
from reflex.components.lucide.icon import Icon from reflex.components.lucide.icon import Icon
from reflex.components.sonner.toast import Toaster, ToastProps from reflex.components.sonner.toast import Toaster, ToastProps
from reflex.constants.compiler import CompileVars from reflex.constants.compiler import CompileVars
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
from reflex.vars import VarData from reflex.vars import VarData
@ -89,21 +89,21 @@ class ConnectionToaster(Toaster):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ConnectionToaster": ) -> "ConnectionToaster":
"""Create a connection toaster component. """Create a connection toaster component.
@ -149,21 +149,21 @@ class ConnectionBanner(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ConnectionBanner": ) -> "ConnectionBanner":
"""Create a connection banner component. """Create a connection banner component.
@ -188,21 +188,21 @@ class ConnectionModal(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ConnectionModal": ) -> "ConnectionModal":
"""Create a connection banner component. """Create a connection banner component.
@ -228,21 +228,21 @@ class WifiOffPulse(Icon):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "WifiOffPulse": ) -> "WifiOffPulse":
"""Create a wifi_off icon with an animated opacity pulse. """Create a wifi_off icon with an animated opacity pulse.
@ -271,51 +271,232 @@ class ConnectionPulser(Div):
def create( # type: ignore def create( # type: ignore
cls, cls,
*children, *children,
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, access_key: Optional[Union[Var[str], str]] = None,
auto_capitalize: Optional[ auto_capitalize: Optional[
Union[Var[Union[bool, int, str]], bool, int, str] Union[
Literal["characters", "none", "off", "on", "sentences", "words"],
Var[Literal["characters", "none", "off", "on", "sentences", "words"]],
]
] = None, ] = None,
content_editable: Optional[ content_editable: Optional[
Union[Var[Union[bool, int, str]], bool, int, str] Union[
Literal["inherit", "plaintext-only", False, True],
Var[Literal["inherit", "plaintext-only", False, True]],
]
] = None, ] = None,
context_menu: Optional[ context_menu: Optional[Union[Var[str], str]] = None,
Union[Var[Union[bool, int, str]], bool, int, str] dir: Optional[Union[Var[str], str]] = None,
] = None, draggable: Optional[Union[Var[bool], bool]] = None,
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
enter_key_hint: Optional[ enter_key_hint: Optional[
Union[Var[Union[bool, int, str]], bool, int, str] Union[
Literal["done", "enter", "go", "next", "previous", "search", "send"],
Var[
Literal["done", "enter", "go", "next", "previous", "search", "send"]
],
]
] = None, ] = None,
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, hidden: Optional[Union[Var[bool], bool]] = None,
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, input_mode: Optional[
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, Union[
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, Literal[
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "decimal",
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "email",
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "none",
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "numeric",
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "search",
"tel",
"text",
"url",
],
Var[
Literal[
"decimal",
"email",
"none",
"numeric",
"search",
"tel",
"text",
"url",
]
],
]
] = None,
item_prop: Optional[Union[Var[str], str]] = None,
lang: Optional[Union[Var[str], str]] = None,
role: Optional[
Union[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
],
Var[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
]
],
]
] = None,
slot: Optional[Union[Var[str], str]] = None,
spell_check: Optional[Union[Var[bool], bool]] = None,
tab_index: Optional[Union[Var[int], int]] = None,
title: Optional[Union[Var[str], str]] = None,
style: Optional[Style] = None, style: Optional[Style] = None,
key: Optional[Any] = None, key: Optional[Any] = None,
id: Optional[Any] = None, id: Optional[Any] = None,
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ConnectionPulser": ) -> "ConnectionPulser":
"""Create a connection pulser component. """Create a connection pulser component.
@ -350,7 +531,274 @@ class ConnectionPulser(Div):
""" """
... ...
class BackendDisabled(Div):
@overload
@classmethod
def create( # type: ignore
cls,
*children,
access_key: Optional[Union[Var[str], str]] = None,
auto_capitalize: Optional[
Union[
Literal["characters", "none", "off", "on", "sentences", "words"],
Var[Literal["characters", "none", "off", "on", "sentences", "words"]],
]
] = None,
content_editable: Optional[
Union[
Literal["inherit", "plaintext-only", False, True],
Var[Literal["inherit", "plaintext-only", False, True]],
]
] = None,
context_menu: Optional[Union[Var[str], str]] = None,
dir: Optional[Union[Var[str], str]] = None,
draggable: Optional[Union[Var[bool], bool]] = None,
enter_key_hint: Optional[
Union[
Literal["done", "enter", "go", "next", "previous", "search", "send"],
Var[
Literal["done", "enter", "go", "next", "previous", "search", "send"]
],
]
] = None,
hidden: Optional[Union[Var[bool], bool]] = None,
input_mode: Optional[
Union[
Literal[
"decimal",
"email",
"none",
"numeric",
"search",
"tel",
"text",
"url",
],
Var[
Literal[
"decimal",
"email",
"none",
"numeric",
"search",
"tel",
"text",
"url",
]
],
]
] = None,
item_prop: Optional[Union[Var[str], str]] = None,
lang: Optional[Union[Var[str], str]] = None,
role: Optional[
Union[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
],
Var[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
]
],
]
] = None,
slot: Optional[Union[Var[str], str]] = None,
spell_check: Optional[Union[Var[bool], bool]] = None,
tab_index: Optional[Union[Var[int], int]] = None,
title: Optional[Union[Var[str], str]] = None,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[()]] = None,
**props,
) -> "BackendDisabled":
"""Create a backend disabled component.
Args:
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.
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
draggable: Defines whether the element can be dragged.
enter_key_hint: Hints what media types the media element is able to play.
hidden: Defines whether the element is hidden.
input_mode: Defines the type of the element.
item_prop: Defines the name of the element for metadata purposes.
lang: Defines the language used in the element.
role: Defines the role of the element.
slot: Assigns a slot in a shadow DOM shadow tree to an element.
spell_check: Defines whether the element may be checked for spelling errors.
tab_index: Defines the position of the current element in the tabbing order.
title: Defines a tooltip for the element.
style: The style of the component.
key: A unique key for the component.
id: The id for the component.
class_name: The class name for the component.
autofocus: Whether the component should take the focus once the page is loaded
custom_attrs: custom attribute
**props: The properties of the component.
Returns:
The backend disabled component.
"""
...
connection_banner = ConnectionBanner.create connection_banner = ConnectionBanner.create
connection_modal = ConnectionModal.create connection_modal = ConnectionModal.create
connection_toaster = ConnectionToaster.create connection_toaster = ConnectionToaster.create
connection_pulser = ConnectionPulser.create connection_pulser = ConnectionPulser.create
backend_disabled = BackendDisabled.create

View File

@ -18,7 +18,7 @@ def set_breakpoints(values: Tuple[str, str, str, str, str]):
breakpoints_values.extend(values) breakpoints_values.extend(values)
K = TypeVar("K") K = TypeVar("K", bound=str)
V = TypeVar("V") V = TypeVar("V")
@ -82,7 +82,9 @@ class Breakpoints(Dict[K, V]):
return Breakpoints( return Breakpoints(
{ {
k: v k: v
for k, v in zip(["initial", *breakpoint_names], thresholds) for k, v in zip(
["initial", *breakpoint_names], thresholds, strict=True
)
if v is not None if v is not None
} }
) )

View File

@ -41,7 +41,7 @@ class ClientSideRouting(Component):
return "" return ""
def wait_for_client_redirect(component) -> Component: def wait_for_client_redirect(component: Component) -> Component:
"""Wait for a redirect to occur before rendering a component. """Wait for a redirect to occur before rendering a component.
This prevents the 404 page from flashing while the redirect is happening. This prevents the 404 page from flashing while the redirect is happening.

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -26,21 +26,21 @@ class ClientSideRouting(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ClientSideRouting": ) -> "ClientSideRouting":
"""Create the component. """Create the component.
@ -60,7 +60,7 @@ class ClientSideRouting(Component):
""" """
... ...
def wait_for_client_redirect(component) -> Component: ... def wait_for_client_redirect(component: Component) -> Component: ...
class Default404Page(Component): class Default404Page(Component):
@overload @overload
@ -75,21 +75,21 @@ class Default404Page(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Default404Page": ) -> "Default404Page":
"""Create the component. """Create the component.

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, List, Optional, Union, overload from typing import Any, Dict, List, Optional, Union, overload
from reflex.components.base.fragment import Fragment from reflex.components.base.fragment import Fragment
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
from reflex.vars.base import Var from reflex.vars.base import Var
@ -27,27 +27,24 @@ class Clipboard(Fragment):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_paste: Optional[ on_paste: Optional[
Union[ Union[EventType[()], EventType[list[tuple[str, str]]]]
EventType[[], BASE_STATE],
EventType[[list[tuple[str, str]]], BASE_STATE],
]
] = None, ] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Clipboard": ) -> "Clipboard":
"""Create a Clipboard component. """Create a Clipboard component.

View File

@ -26,10 +26,9 @@ class Cond(MemoizationLeaf):
cond: Var[Any] cond: Var[Any]
# The component to render if the cond is true. # The component to render if the cond is true.
comp1: BaseComponent = None # type: ignore comp1: BaseComponent | None = None
# The component to render if the cond is false. # The component to render if the cond is false.
comp2: BaseComponent = None # type: ignore comp2: BaseComponent | None = None
@classmethod @classmethod
def create( def create(
@ -62,19 +61,11 @@ class Cond(MemoizationLeaf):
) )
) )
def _get_props_imports(self):
"""Get the imports needed for component's props.
Returns:
The imports for the component's props of the component.
"""
return []
def _render(self) -> Tag: def _render(self) -> Tag:
return CondTag( return CondTag(
cond=self.cond, cond=self.cond,
true_value=self.comp1.render(), true_value=self.comp1.render(), # pyright: ignore [reportOptionalMemberAccess]
false_value=self.comp2.render(), false_value=self.comp2.render(), # pyright: ignore [reportOptionalMemberAccess]
) )
def render(self) -> Dict: def render(self) -> Dict:
@ -111,7 +102,7 @@ class Cond(MemoizationLeaf):
@overload @overload
def cond(condition: Any, c1: Component, c2: Any) -> Component: ... def cond(condition: Any, c1: Component, c2: Any) -> Component: ... # pyright: ignore [reportOverlappingOverload]
@overload @overload
@ -154,7 +145,7 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
if c2 is None: if c2 is None:
raise ValueError("For conditional vars, the second argument must be set.") raise ValueError("For conditional vars, the second argument must be set.")
def create_var(cond_part): def create_var(cond_part: Any) -> Var[Any]:
return LiteralVar.create(cond_part) return LiteralVar.create(cond_part)
# convert the truth and false cond parts into vars so the _var_data can be obtained. # convert the truth and false cond parts into vars so the _var_data can be obtained.
@ -163,16 +154,16 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
# Create the conditional var. # Create the conditional var.
return ternary_operation( return ternary_operation(
cond_var.bool()._replace( # type: ignore cond_var.bool()._replace(
merge_var_data=VarData(imports=_IS_TRUE_IMPORT), merge_var_data=VarData(imports=_IS_TRUE_IMPORT),
), # type: ignore ),
c1, c1,
c2, c2,
) )
@overload @overload
def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... # type: ignore def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... # pyright: ignore [reportOverlappingOverload]
@overload @overload

View File

@ -28,7 +28,7 @@ class DebounceInput(Component):
min_length: Var[int] min_length: Var[int]
# Time to wait between end of input and triggering on_change # Time to wait between end of input and triggering on_change
debounce_timeout: Var[int] = DEFAULT_DEBOUNCE_TIMEOUT # type: ignore debounce_timeout: Var[int] = Var.create(DEFAULT_DEBOUNCE_TIMEOUT)
# If true, notify when Enter key is pressed # If true, notify when Enter key is pressed
force_notify_by_enter: Var[bool] force_notify_by_enter: Var[bool]

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Type, Union, overload from typing import Any, Dict, Optional, Type, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -31,22 +31,22 @@ class DebounceInput(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_change: Optional[EventType[[], BASE_STATE]] = None, on_change: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "DebounceInput": ) -> "DebounceInput":
"""Create a DebounceInput component. """Create a DebounceInput component.

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import functools
import inspect import inspect
from typing import Any, Callable, Iterable from typing import Any, Callable, Iterable
@ -10,6 +11,7 @@ from reflex.components.component import Component
from reflex.components.tags import IterTag from reflex.components.tags import IterTag
from reflex.constants import MemoizationMode from reflex.constants import MemoizationMode
from reflex.state import ComponentState from reflex.state import ComponentState
from reflex.utils.exceptions import UntypedVarError
from reflex.vars.base import LiteralVar, Var from reflex.vars.base import LiteralVar, Var
@ -50,8 +52,12 @@ class Foreach(Component):
Raises: Raises:
ForeachVarError: If the iterable is of type Any. ForeachVarError: If the iterable is of type Any.
TypeError: If the render function is a ComponentState. TypeError: If the render function is a ComponentState.
UntypedVarError: If the iterable is of type Any without a type annotation.
""" """
iterable = LiteralVar.create(iterable) from reflex.vars import ArrayVar, ObjectVar, StringVar
iterable = LiteralVar.create(iterable).guess_type()
if iterable._var_type == Any: if iterable._var_type == Any:
raise ForeachVarError( raise ForeachVarError(
f"Could not foreach over var `{iterable!s}` of type Any. " f"Could not foreach over var `{iterable!s}` of type Any. "
@ -67,12 +73,30 @@ class Foreach(Component):
"Using a ComponentState as `render_fn` inside `rx.foreach` is not supported yet." "Using a ComponentState as `render_fn` inside `rx.foreach` is not supported yet."
) )
if isinstance(iterable, ObjectVar):
iterable = iterable.entries()
if isinstance(iterable, StringVar):
iterable = iterable.split()
if not isinstance(iterable, ArrayVar):
raise ForeachVarError(
f"Could not foreach over var `{iterable!s}` of type {iterable._var_type}. "
"See https://reflex.dev/docs/library/dynamic-rendering/foreach/"
)
component = cls( component = cls(
iterable=iterable, iterable=iterable,
render_fn=render_fn, render_fn=render_fn,
) )
# Keep a ref to a rendered component to determine correct imports/hooks/styles. try:
component.children = [component._render().render_component()] # Keep a ref to a rendered component to determine correct imports/hooks/styles.
component.children = [component._render().render_component()]
except UntypedVarError as e:
raise UntypedVarError(
f"Could not foreach over var `{iterable!s}` without a type annotation. "
"See https://reflex.dev/docs/library/dynamic-rendering/foreach/"
) from e
return component return component
def _render(self) -> IterTag: def _render(self) -> IterTag:
@ -97,9 +121,20 @@ class Foreach(Component):
# Determine the index var name based on the params accepted by render_fn. # Determine the index var name based on the params accepted by render_fn.
props["index_var_name"] = params[1].name props["index_var_name"] = params[1].name
else: else:
render_fn = self.render_fn
# Otherwise, use a deterministic index, based on the render function bytecode. # Otherwise, use a deterministic index, based on the render function bytecode.
code_hash = ( code_hash = (
hash(self.render_fn.__code__) hash(
getattr(
render_fn,
"__code__",
(
repr(self.render_fn)
if not isinstance(render_fn, functools.partial)
else render_fn.func.__code__
),
)
)
.to_bytes( .to_bytes(
length=8, length=8,
byteorder="big", byteorder="big",

View File

@ -14,7 +14,7 @@ class Html(Div):
""" """
# The HTML to render. # The HTML to render.
dangerouslySetInnerHTML: Var[Dict[str, str]] dangerouslySetInnerHTML: Var[Dict[str, str]] # noqa: N815
@classmethod @classmethod
def create(cls, *children, **props): def create(cls, *children, **props):

View File

@ -3,10 +3,10 @@
# ------------------- DO NOT EDIT ---------------------- # ------------------- DO NOT EDIT ----------------------
# This file was generated by `reflex/utils/pyi_generator.py`! # This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------ # ------------------------------------------------------
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Literal, Optional, Union, overload
from reflex.components.el.elements.typography import Div from reflex.components.el.elements.typography import Div
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -19,51 +19,232 @@ class Html(Div):
dangerouslySetInnerHTML: Optional[ dangerouslySetInnerHTML: Optional[
Union[Dict[str, str], Var[Dict[str, str]]] Union[Dict[str, str], Var[Dict[str, str]]]
] = None, ] = None,
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, access_key: Optional[Union[Var[str], str]] = None,
auto_capitalize: Optional[ auto_capitalize: Optional[
Union[Var[Union[bool, int, str]], bool, int, str] Union[
Literal["characters", "none", "off", "on", "sentences", "words"],
Var[Literal["characters", "none", "off", "on", "sentences", "words"]],
]
] = None, ] = None,
content_editable: Optional[ content_editable: Optional[
Union[Var[Union[bool, int, str]], bool, int, str] Union[
Literal["inherit", "plaintext-only", False, True],
Var[Literal["inherit", "plaintext-only", False, True]],
]
] = None, ] = None,
context_menu: Optional[ context_menu: Optional[Union[Var[str], str]] = None,
Union[Var[Union[bool, int, str]], bool, int, str] dir: Optional[Union[Var[str], str]] = None,
] = None, draggable: Optional[Union[Var[bool], bool]] = None,
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
enter_key_hint: Optional[ enter_key_hint: Optional[
Union[Var[Union[bool, int, str]], bool, int, str] Union[
Literal["done", "enter", "go", "next", "previous", "search", "send"],
Var[
Literal["done", "enter", "go", "next", "previous", "search", "send"]
],
]
] = None, ] = None,
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, hidden: Optional[Union[Var[bool], bool]] = None,
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, input_mode: Optional[
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, Union[
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, Literal[
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "decimal",
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "email",
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "none",
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "numeric",
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "search",
"tel",
"text",
"url",
],
Var[
Literal[
"decimal",
"email",
"none",
"numeric",
"search",
"tel",
"text",
"url",
]
],
]
] = None,
item_prop: Optional[Union[Var[str], str]] = None,
lang: Optional[Union[Var[str], str]] = None,
role: Optional[
Union[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
],
Var[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
]
],
]
] = None,
slot: Optional[Union[Var[str], str]] = None,
spell_check: Optional[Union[Var[bool], bool]] = None,
tab_index: Optional[Union[Var[int], int]] = None,
title: Optional[Union[Var[str], str]] = None,
style: Optional[Style] = None, style: Optional[Style] = None,
key: Optional[Any] = None, key: Optional[Any] = None,
id: Optional[Any] = None, id: Optional[Any] = None,
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Html": ) -> "Html":
"""Create a html component. """Create a html component.

View File

@ -109,7 +109,7 @@ class Match(MemoizationLeaf):
return cases, default return cases, default
@classmethod @classmethod
def _create_case_var_with_var_data(cls, case_element): def _create_case_var_with_var_data(cls, case_element: Any) -> Var:
"""Convert a case element into a Var.If the case """Convert a case element into a Var.If the case
is a Style type, we extract the var data and merge it with the is a Style type, we extract the var data and merge it with the
newly created Var. newly created Var.
@ -178,9 +178,9 @@ class Match(MemoizationLeaf):
first_case_return = match_cases[0][-1] first_case_return = match_cases[0][-1]
return_type = type(first_case_return) return_type = type(first_case_return)
if types._isinstance(first_case_return, BaseComponent): if isinstance(first_case_return, BaseComponent):
return_type = BaseComponent return_type = BaseComponent
elif types._isinstance(first_case_return, Var): elif isinstance(first_case_return, Var):
return_type = Var return_type = Var
for index, case in enumerate(match_cases): for index, case in enumerate(match_cases):
@ -222,27 +222,27 @@ class Match(MemoizationLeaf):
cond=match_cond_var, cond=match_cond_var,
match_cases=match_cases, match_cases=match_cases,
default=default, default=default,
children=[case[-1] for case in match_cases] + [default], # type: ignore children=[case[-1] for case in match_cases] + [default], # pyright: ignore [reportArgumentType]
) )
) )
# Validate the match cases (as well as the default case) to have Var return types. # Validate the match cases (as well as the default case) to have Var return types.
if any( if any(
case for case in match_cases if not types._isinstance(case[-1], Var) case for case in match_cases if not isinstance(case[-1], Var)
) or not types._isinstance(default, Var): ) or not isinstance(default, Var):
raise ValueError("Return types of match cases should be Vars.") raise ValueError("Return types of match cases should be Vars.")
return Var( return Var(
_js_expr=format.format_match( _js_expr=format.format_match(
cond=str(match_cond_var), cond=str(match_cond_var),
match_cases=match_cases, match_cases=match_cases,
default=default, # type: ignore default=default, # pyright: ignore [reportArgumentType]
), ),
_var_type=default._var_type, # type: ignore _var_type=default._var_type, # pyright: ignore [reportAttributeAccessIssue,reportOptionalMemberAccess]
_var_data=VarData.merge( _var_data=VarData.merge(
match_cond_var._get_all_var_data(), match_cond_var._get_all_var_data(),
*[el._get_all_var_data() for case in match_cases for el in case], *[el._get_all_var_data() for case in match_cases for el in case],
default._get_all_var_data(), # type: ignore default._get_all_var_data(), # pyright: ignore [reportAttributeAccessIssue, reportOptionalMemberAccess]
), ),
) )

View File

@ -0,0 +1,134 @@
"""Components for displaying the Reflex sticky logo."""
from reflex.components.component import ComponentNamespace
from reflex.components.core.colors import color
from reflex.components.core.cond import color_mode_cond
from reflex.components.core.responsive import desktop_only
from reflex.components.el.elements.inline import A
from reflex.components.el.elements.media import Path, Rect, Svg
from reflex.components.radix.themes.typography.text import Text
from reflex.style import Style
class StickyLogo(Svg):
"""A simple Reflex logo SVG with only the letter R."""
@classmethod
def create(cls):
"""Create the simple Reflex logo SVG.
Returns:
The simple Reflex logo SVG.
"""
return super().create(
Rect.create(width="16", height="16", rx="2", fill="#6E56CF"),
Path.create(d="M10 9V13H12V9H10Z", fill="white"),
Path.create(d="M4 3V13H6V9H10V7H6V5H10V7H12V3H4Z", fill="white"),
width="16",
height="16",
viewBox="0 0 16 16",
xmlns="http://www.w3.org/2000/svg",
)
def add_style(self):
"""Add the style to the component.
Returns:
The style of the component.
"""
return Style(
{
"fill": "white",
}
)
class StickyLabel(Text):
"""A label that displays the Reflex sticky."""
@classmethod
def create(cls):
"""Create the sticky label.
Returns:
The sticky label.
"""
return super().create("Built with Reflex")
def add_style(self):
"""Add the style to the component.
Returns:
The style of the component.
"""
return Style(
{
"color": color("slate", 1),
"font_weight": "600",
"font_family": "'Instrument Sans', sans-serif",
"font_size": "0.875rem",
"line_height": "1rem",
"letter_spacing": "-0.00656rem",
}
)
class StickyBadge(A):
"""A badge that displays the Reflex sticky logo."""
@classmethod
def create(cls):
"""Create the sticky badge.
Returns:
The sticky badge.
"""
return super().create(
StickyLogo.create(),
desktop_only(StickyLabel.create()),
href="https://reflex.dev",
target="_blank",
width="auto",
padding="0.375rem",
align="center",
text_align="center",
)
def add_style(self):
"""Add the style to the component.
Returns:
The style of the component.
"""
return Style(
{
"position": "fixed",
"bottom": "1rem",
"right": "1rem",
"display": "flex",
"flex-direction": "row",
"gap": "0.375rem",
"align-items": "center",
"width": "auto",
"border-radius": "0.5rem",
"color": color_mode_cond("#E5E7EB", "#27282B"),
"border": color_mode_cond("1px solid #27282B", "1px solid #E5E7EB"),
"background-color": color_mode_cond("#151618", "#FCFCFD"),
"padding": "0.375rem",
"transition": "background-color 0.2s ease-in-out",
"box-shadow": "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
"z-index": "9998",
"cursor": "pointer",
},
)
class StickyNamespace(ComponentNamespace):
"""Sticky components namespace."""
__call__ = staticmethod(StickyBadge.create)
label = staticmethod(StickyLabel.create)
logo = staticmethod(StickyLogo.create)
sticky = StickyNamespace()

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@ from reflex.event import (
from reflex.utils import format from reflex.utils import format
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
from reflex.vars import VarData from reflex.vars import VarData
from reflex.vars.base import CallableVar, Var, get_unique_variable_name from reflex.vars.base import Var, get_unique_variable_name
from reflex.vars.sequence import LiteralStringVar from reflex.vars.sequence import LiteralStringVar
DEFAULT_UPLOAD_ID: str = "default" DEFAULT_UPLOAD_ID: str = "default"
@ -45,7 +45,6 @@ upload_files_context_var_data: VarData = VarData(
) )
@CallableVar
def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> Var: def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> Var:
"""Get the file upload drop trigger. """Get the file upload drop trigger.
@ -75,7 +74,6 @@ def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> Var:
) )
@CallableVar
def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> Var: def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> Var:
"""Get the list of selected files. """Get the list of selected files.
@ -149,7 +147,7 @@ uploaded_files_url_prefix = Var(
).to(str) ).to(str)
def get_upload_url(file_path: str) -> Var[str]: def get_upload_url(file_path: str | Var[str]) -> Var[str]:
"""Get the URL of an uploaded file. """Get the URL of an uploaded file.
Args: Args:
@ -160,7 +158,7 @@ def get_upload_url(file_path: str) -> Var[str]:
""" """
Upload.is_used = True Upload.is_used = True
return uploaded_files_url_prefix + "/" + file_path return Var.create(f"{uploaded_files_url_prefix}/{file_path}")
def _on_drop_spec(files: Var) -> Tuple[Var[Any]]: def _on_drop_spec(files: Var) -> Tuple[Var[Any]]:
@ -192,7 +190,7 @@ class GhostUpload(Fragment):
class Upload(MemoizationLeaf): class Upload(MemoizationLeaf):
"""A file upload component.""" """A file upload component."""
library = "react-dropzone@14.2.10" library = "react-dropzone@14.3.5"
tag = "" tag = ""
@ -269,7 +267,7 @@ class Upload(MemoizationLeaf):
on_drop = upload_props["on_drop"] on_drop = upload_props["on_drop"]
if isinstance(on_drop, Callable): if isinstance(on_drop, Callable):
# Call the lambda to get the event chain. # Call the lambda to get the event chain.
on_drop = call_event_fn(on_drop, _on_drop_spec) # type: ignore on_drop = call_event_fn(on_drop, _on_drop_spec)
if isinstance(on_drop, EventSpec): if isinstance(on_drop, EventSpec):
# Update the provided args for direct use with on_drop. # Update the provided args for direct use with on_drop.
on_drop = on_drop.with_args( on_drop = on_drop.with_args(

View File

@ -9,18 +9,16 @@ from typing import Any, ClassVar, Dict, List, Optional, Union, overload
from reflex.components.base.fragment import Fragment from reflex.components.base.fragment import Fragment
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf
from reflex.constants import Dirs from reflex.constants import Dirs
from reflex.event import BASE_STATE, CallableEventSpec, EventSpec, EventType from reflex.event import CallableEventSpec, EventSpec, EventType
from reflex.style import Style from reflex.style import Style
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
from reflex.vars import VarData from reflex.vars import VarData
from reflex.vars.base import CallableVar, Var from reflex.vars.base import Var
DEFAULT_UPLOAD_ID: str DEFAULT_UPLOAD_ID: str
upload_files_context_var_data: VarData upload_files_context_var_data: VarData
@CallableVar
def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> Var: ... def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> Var: ...
@CallableVar
def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> Var: ... def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> Var: ...
@CallableEventSpec @CallableEventSpec
def clear_selected_files(id_: str = DEFAULT_UPLOAD_ID) -> EventSpec: ... def clear_selected_files(id_: str = DEFAULT_UPLOAD_ID) -> EventSpec: ...
@ -37,7 +35,7 @@ uploaded_files_url_prefix = Var(
), ),
).to(str) ).to(str)
def get_upload_url(file_path: str) -> Var[str]: ... def get_upload_url(file_path: str | Var[str]) -> Var[str]: ...
class UploadFilesProvider(Component): class UploadFilesProvider(Component):
@overload @overload
@ -51,21 +49,21 @@ class UploadFilesProvider(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "UploadFilesProvider": ) -> "UploadFilesProvider":
"""Create the component. """Create the component.
@ -97,24 +95,22 @@ class GhostUpload(Fragment):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_drop: Optional[ on_drop: Optional[Union[EventType[()], EventType[Any]]] = None,
Union[EventType[[], BASE_STATE], EventType[[Any], BASE_STATE]] on_focus: Optional[EventType[()]] = None,
] = None, on_mount: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
**props, **props,
) -> "GhostUpload": ) -> "GhostUpload":
"""Create the component. """Create the component.
@ -158,24 +154,22 @@ class Upload(MemoizationLeaf):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_drop: Optional[ on_drop: Optional[Union[EventType[()], EventType[Any]]] = None,
Union[EventType[[], BASE_STATE], EventType[[Any], BASE_STATE]] on_focus: Optional[EventType[()]] = None,
] = None, on_mount: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
**props, **props,
) -> "Upload": ) -> "Upload":
"""Create an upload component. """Create an upload component.
@ -226,24 +220,22 @@ class StyledUpload(Upload):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_drop: Optional[ on_drop: Optional[Union[EventType[()], EventType[Any]]] = None,
Union[EventType[[], BASE_STATE], EventType[[Any], BASE_STATE]] on_focus: Optional[EventType[()]] = None,
] = None, on_mount: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
**props, **props,
) -> "StyledUpload": ) -> "StyledUpload":
"""Create the styled upload component. """Create the styled upload component.
@ -294,24 +286,22 @@ class UploadNamespace(ComponentNamespace):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_drop: Optional[ on_drop: Optional[Union[EventType[()], EventType[Any]]] = None,
Union[EventType[[], BASE_STATE], EventType[[Any], BASE_STATE]] on_focus: Optional[EventType[()]] = None,
] = None, on_mount: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
**props, **props,
) -> "StyledUpload": ) -> "StyledUpload":
"""Create the styled upload component. """Create the styled upload component.

View File

@ -3,6 +3,7 @@
from __future__ import annotations from __future__ import annotations
import dataclasses import dataclasses
import typing
from typing import ClassVar, Dict, Literal, Optional, Union from typing import ClassVar, Dict, Literal, Optional, Union
from reflex.components.component import Component, ComponentNamespace from reflex.components.component import Component, ComponentNamespace
@ -14,7 +15,7 @@ from reflex.components.radix.themes.layout.box import Box
from reflex.constants.colors import Color from reflex.constants.colors import Color
from reflex.event import set_clipboard from reflex.event import set_clipboard
from reflex.style import Style from reflex.style import Style
from reflex.utils import console, format from reflex.utils import format
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
from reflex.vars.base import LiteralVar, Var, VarData from reflex.vars.base import LiteralVar, Var, VarData
@ -382,7 +383,7 @@ for theme_name in dir(Theme):
class CodeBlock(Component, MarkdownComponentMap): class CodeBlock(Component, MarkdownComponentMap):
"""A code block.""" """A code block."""
library = "react-syntax-highlighter@15.6.0" library = "react-syntax-highlighter@15.6.1"
tag = "PrismAsyncLight" tag = "PrismAsyncLight"
@ -438,6 +439,8 @@ class CodeBlock(Component, MarkdownComponentMap):
can_copy = props.pop("can_copy", False) can_copy = props.pop("can_copy", False)
copy_button = props.pop("copy_button", None) copy_button = props.pop("copy_button", None)
# react-syntax-highlighter doesn't have an explicit "light" or "dark" theme so we use one-light and one-dark
# themes respectively to ensure code compatibility.
if "theme" not in props: if "theme" not in props:
# Default color scheme responds to global color mode. # Default color scheme responds to global color mode.
props["theme"] = color_mode_cond( props["theme"] = color_mode_cond(
@ -445,20 +448,9 @@ class CodeBlock(Component, MarkdownComponentMap):
dark=Theme.one_dark, dark=Theme.one_dark,
) )
# react-syntax-highlighter doesn't have an explicit "light" or "dark" theme so we use one-light and one-dark
# themes respectively to ensure code compatibility.
if "theme" in props and not isinstance(props["theme"], Var):
props["theme"] = getattr(Theme, format.to_snake_case(props["theme"])) # type: ignore
console.deprecate(
feature_name="theme prop as string",
reason="Use code_block.themes instead.",
deprecation_version="0.6.0",
removal_version="0.7.0",
)
if can_copy: if can_copy:
code = children[0] code = children[0]
copy_button = ( # type: ignore copy_button = (
copy_button copy_button
if copy_button is not None if copy_button is not None
else Button.create( else Button.create(
@ -512,7 +504,7 @@ class CodeBlock(Component, MarkdownComponentMap):
return ["can_copy", "copy_button"] return ["can_copy", "copy_button"]
@classmethod @classmethod
def _get_language_registration_hook(cls, language_var: Var = _LANGUAGE) -> str: def _get_language_registration_hook(cls, language_var: Var = _LANGUAGE) -> Var:
"""Get the hook to register the language. """Get the hook to register the language.
Args: Args:
@ -523,21 +515,46 @@ class CodeBlock(Component, MarkdownComponentMap):
Returns: Returns:
The hook to register the language. The hook to register the language.
""" """
return f""" language_in_there = Var.create(typing.get_args(LiteralCodeLanguage)).contains(
if ({language_var!s}) {{ language_var
(async () => {{ )
try {{ async_load = f"""
(async () => {{
try {{
const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${{{language_var!s}}}`); const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${{{language_var!s}}}`);
SyntaxHighlighter.registerLanguage({language_var!s}, module.default); SyntaxHighlighter.registerLanguage({language_var!s}, module.default);
}} catch (error) {{ }} catch (error) {{
console.error(`Error importing language module for ${{{language_var!s}}}:`, error); console.error(`Language ${{{language_var!s}}} is not supported for code blocks inside of markdown: `, error);
}} }}
}})(); }})();
"""
return Var(
f"""
if ({language_var!s}) {{
if (!{language_in_there!s}) {{
console.warn(`Language \\`${{{language_var!s}}}\\` is not supported for code blocks inside of markdown.`);
{language_var!s} = '';
}} else {{
{async_load!s}
}}
}} }}
""" """
if not isinstance(language_var, LiteralVar)
else f"""
if ({language_var!s}) {{
{async_load!s}
}}""",
_var_data=VarData(
imports={
cls.__fields__["library"].default: [
ImportVar(tag="PrismAsyncLight", alias="SyntaxHighlighter")
]
},
),
)
@classmethod @classmethod
def get_component_map_custom_code(cls) -> str: def get_component_map_custom_code(cls) -> Var:
"""Get the custom code for the component. """Get the custom code for the component.
Returns: Returns:

View File

@ -9,7 +9,7 @@ from typing import Any, ClassVar, Dict, Literal, Optional, Union, overload
from reflex.components.component import Component, ComponentNamespace from reflex.components.component import Component, ComponentNamespace
from reflex.components.markdown.markdown import MarkdownComponentMap from reflex.components.markdown.markdown import MarkdownComponentMap
from reflex.constants.colors import Color from reflex.constants.colors import Color
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -938,21 +938,21 @@ class CodeBlock(Component, MarkdownComponentMap):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "CodeBlock": ) -> "CodeBlock":
"""Create a text component. """Create a text component.
@ -984,7 +984,7 @@ class CodeBlock(Component, MarkdownComponentMap):
def add_style(self): ... def add_style(self): ...
@classmethod @classmethod
def get_component_map_custom_code(cls) -> str: ... def get_component_map_custom_code(cls) -> Var: ...
def add_hooks(self) -> list[str | Var]: ... def add_hooks(self) -> list[str | Var]: ...
class CodeblockNamespace(ComponentNamespace): class CodeblockNamespace(ComponentNamespace):
@ -1576,21 +1576,21 @@ class CodeblockNamespace(ComponentNamespace):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "CodeBlock": ) -> "CodeBlock":
"""Create a text component. """Create a text component.

View File

@ -3,9 +3,7 @@
from __future__ import annotations from __future__ import annotations
from enum import Enum from enum import Enum
from typing import Any, Dict, List, Literal, Optional, Tuple, Union from typing import Any, Dict, List, Literal, Optional, Tuple, TypedDict, Union
from typing_extensions import TypedDict
from reflex.base import Base from reflex.base import Base
from reflex.components.component import Component, NoSSRComponent from reflex.components.component import Component, NoSSRComponent
@ -165,7 +163,7 @@ class DataEditor(NoSSRComponent):
tag = "DataEditor" tag = "DataEditor"
is_default = True is_default = True
library: str = "@glideapps/glide-data-grid@^6.0.3" library: str | None = "@glideapps/glide-data-grid@^6.0.3"
lib_dependencies: List[str] = [ lib_dependencies: List[str] = [
"lodash@^4.17.21", "lodash@^4.17.21",
"react-responsive-carousel@^3.2.7", "react-responsive-carousel@^3.2.7",
@ -321,6 +319,8 @@ class DataEditor(NoSSRComponent):
Returns: Returns:
The import dict. The import dict.
""" """
if self.library is None:
return {}
return { return {
"": f"{format.format_library_name(self.library)}/dist/index.css", "": f"{format.format_library_name(self.library)}/dist/index.css",
self.library: "GridCellKind", self.library: "GridCellKind",
@ -343,9 +343,9 @@ class DataEditor(NoSSRComponent):
data_callback = self.get_cell_content._js_expr data_callback = self.get_cell_content._js_expr
else: else:
data_callback = f"getData_{editor_id}" data_callback = f"getData_{editor_id}"
self.get_cell_content = Var(_js_expr=data_callback) # type: ignore self.get_cell_content = Var(_js_expr=data_callback)
code = [f"function {data_callback}([col, row])" "{"] code = [f"function {data_callback}([col, row]){{"]
columns_path = str(self.columns) columns_path = str(self.columns)
data_path = str(self.data) data_path = str(self.data)
@ -385,7 +385,8 @@ class DataEditor(NoSSRComponent):
raise ValueError( raise ValueError(
"DataEditor data must be an ArrayVar if rows is not provided." "DataEditor data must be an ArrayVar if rows is not provided."
) )
props["rows"] = data.length() if isinstance(data, Var) else len(data)
props["rows"] = data.length() if isinstance(data, ArrayVar) else len(data)
if not isinstance(columns, Var) and len(columns): if not isinstance(columns, Var) and len(columns):
if types.is_dataframe(type(data)) or ( if types.is_dataframe(type(data)) or (

View File

@ -4,13 +4,11 @@
# This file was generated by `reflex/utils/pyi_generator.py`! # This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------ # ------------------------------------------------------
from enum import Enum from enum import Enum
from typing import Any, Dict, List, Literal, Optional, Union, overload from typing import Any, Dict, List, Literal, Optional, TypedDict, Union, overload
from typing_extensions import TypedDict
from reflex.base import Base from reflex.base import Base
from reflex.components.component import NoSSRComponent from reflex.components.component import NoSSRComponent
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.utils.imports import ImportDict from reflex.utils.imports import ImportDict
from reflex.utils.serializers import serializer from reflex.utils.serializers import serializer
@ -183,93 +181,79 @@ class DataEditor(NoSSRComponent):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_cell_activated: Optional[ on_cell_activated: Optional[
Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]] Union[EventType[()], EventType[tuple[int, int]]]
] = None, ] = None,
on_cell_clicked: Optional[ on_cell_clicked: Optional[
Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]] Union[EventType[()], EventType[tuple[int, int]]]
] = None, ] = None,
on_cell_context_menu: Optional[ on_cell_context_menu: Optional[
Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]] Union[EventType[()], EventType[tuple[int, int]]]
] = None, ] = None,
on_cell_edited: Optional[ on_cell_edited: Optional[
Union[ Union[
EventType[[], BASE_STATE], EventType[()],
EventType[[tuple[int, int]], BASE_STATE], EventType[tuple[int, int]],
EventType[[tuple[int, int], GridCell], BASE_STATE], EventType[tuple[int, int], GridCell],
] ]
] = None, ] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_column_resize: Optional[ on_column_resize: Optional[
Union[ Union[EventType[()], EventType[GridColumn], EventType[GridColumn, int]]
EventType[[], BASE_STATE],
EventType[[GridColumn], BASE_STATE],
EventType[[GridColumn, int], BASE_STATE],
]
] = None, ] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_delete: Optional[ on_delete: Optional[Union[EventType[()], EventType[GridSelection]]] = None,
Union[EventType[[], BASE_STATE], EventType[[GridSelection], BASE_STATE]] on_double_click: Optional[EventType[()]] = None,
] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None,
on_finished_editing: Optional[ on_finished_editing: Optional[
Union[ Union[
EventType[[], BASE_STATE], EventType[()],
EventType[[Union[GridCell, None]], BASE_STATE], EventType[Union[GridCell, None]],
EventType[[Union[GridCell, None], tuple[int, int]], BASE_STATE], EventType[Union[GridCell, None], tuple[int, int]],
] ]
] = None, ] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_group_header_clicked: Optional[ on_group_header_clicked: Optional[
Union[ Union[
EventType[[], BASE_STATE], EventType[()],
EventType[[tuple[int, int]], BASE_STATE], EventType[tuple[int, int]],
EventType[[tuple[int, int], GridCell], BASE_STATE], EventType[tuple[int, int], GridCell],
] ]
] = None, ] = None,
on_group_header_context_menu: Optional[ on_group_header_context_menu: Optional[
Union[ Union[
EventType[[], BASE_STATE], EventType[()],
EventType[[int], BASE_STATE], EventType[int],
EventType[[int, GroupHeaderClickedEventArgs], BASE_STATE], EventType[int, GroupHeaderClickedEventArgs],
] ]
] = None, ] = None,
on_group_header_renamed: Optional[ on_group_header_renamed: Optional[
Union[ Union[EventType[()], EventType[str], EventType[str, str]]
EventType[[], BASE_STATE],
EventType[[str], BASE_STATE],
EventType[[str, str], BASE_STATE],
]
] = None, ] = None,
on_header_clicked: Optional[ on_header_clicked: Optional[
Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]] Union[EventType[()], EventType[tuple[int, int]]]
] = None, ] = None,
on_header_context_menu: Optional[ on_header_context_menu: Optional[
Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]] Union[EventType[()], EventType[tuple[int, int]]]
] = None, ] = None,
on_header_menu_click: Optional[ on_header_menu_click: Optional[
Union[ Union[EventType[()], EventType[int], EventType[int, Rectangle]]
EventType[[], BASE_STATE],
EventType[[int], BASE_STATE],
EventType[[int, Rectangle], BASE_STATE],
]
] = None, ] = None,
on_item_hovered: Optional[ on_item_hovered: Optional[
Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]] Union[EventType[()], EventType[tuple[int, int]]]
] = None, ] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_row_appended: Optional[EventType[[], BASE_STATE]] = None, on_row_appended: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_selection_cleared: Optional[EventType[[], BASE_STATE]] = None, on_selection_cleared: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "DataEditor": ) -> "DataEditor":
"""Create the DataEditor component. """Create the DataEditor component.

View File

@ -5,20 +5,22 @@ from typing import Union
import reflex as rx import reflex as rx
def svg_logo(color: Union[str, rx.Var[str]] = rx.color_mode_cond("#110F1F", "white")): def svg_logo(
color: Union[str, rx.Var[str]] = rx.color_mode_cond("#110F1F", "white"),
**props,
):
"""A Reflex logo SVG. """A Reflex logo SVG.
Args: Args:
color: The color of the logo. color: The color of the logo.
props: Extra props to pass to the svg component.
Returns: Returns:
The Reflex logo SVG. The Reflex logo SVG.
""" """
def logo_path(d): def logo_path(d: str):
return rx.el.svg.path( return rx.el.svg.path(d=d)
d=d,
)
paths = [ paths = [
"M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z", "M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z",
@ -31,11 +33,14 @@ def svg_logo(color: Union[str, rx.Var[str]] = rx.color_mode_cond("#110F1F", "whi
return rx.el.svg( return rx.el.svg(
*[logo_path(d) for d in paths], *[logo_path(d) for d in paths],
width="56", rx.el.title("Reflex"),
height="12", aria_label="Reflex",
viewBox="0 0 56 12", role="img",
width=props.pop("width", "56"),
height=props.pop("height", "12"),
fill=color, fill=color,
xmlns="http://www.w3.org/2000/svg", xmlns="http://www.w3.org/2000/svg",
**props,
) )

View File

@ -602,7 +602,7 @@ class ShikiCodeBlock(Component, MarkdownComponentMap):
transformer_styles = {} transformer_styles = {}
# Collect styles from transformers and wrapper # Collect styles from transformers and wrapper
for transformer in code_block.transformers._var_value: # type: ignore for transformer in code_block.transformers._var_value: # pyright: ignore [reportAttributeAccessIssue]
if isinstance(transformer, ShikiBaseTransformers) and transformer.style: if isinstance(transformer, ShikiBaseTransformers) and transformer.style:
transformer_styles.update(transformer.style) transformer_styles.update(transformer.style)
transformer_styles.update(code_wrapper_props.pop("style", {})) transformer_styles.update(code_wrapper_props.pop("style", {}))
@ -621,18 +621,22 @@ class ShikiCodeBlock(Component, MarkdownComponentMap):
Returns: Returns:
Imports for the component. Imports for the component.
Raises:
ValueError: If the transformers are not of type LiteralVar.
""" """
imports = defaultdict(list) imports = defaultdict(list)
if not isinstance(self.transformers, LiteralVar):
raise ValueError(
f"transformers should be a LiteralVar type. Got {type(self.transformers)} instead."
)
for transformer in self.transformers._var_value: for transformer in self.transformers._var_value:
if isinstance(transformer, ShikiBaseTransformers): if isinstance(transformer, ShikiBaseTransformers):
imports[transformer.library].extend( imports[transformer.library].extend(
[ImportVar(tag=str(fn)) for fn in transformer.fns] [ImportVar(tag=str(fn)) for fn in transformer.fns]
) )
( if transformer.library not in self.lib_dependencies:
self.lib_dependencies.append(transformer.library) self.lib_dependencies.append(transformer.library)
if transformer.library not in self.lib_dependencies
else None
)
return imports return imports
@classmethod @classmethod
@ -653,8 +657,9 @@ class ShikiCodeBlock(Component, MarkdownComponentMap):
raise ValueError( raise ValueError(
f"the function names should be str names of functions in the specified transformer: {library!r}" f"the function names should be str names of functions in the specified transformer: {library!r}"
) )
return ShikiBaseTransformers( # type: ignore return ShikiBaseTransformers(
library=library, fns=[FunctionStringVar.create(fn) for fn in fns] library=library,
fns=[FunctionStringVar.create(fn) for fn in fns], # pyright: ignore [reportCallIssue]
) )
def _render(self, props: dict[str, Any] | None = None): def _render(self, props: dict[str, Any] | None = None):
@ -757,13 +762,13 @@ class ShikiHighLevelCodeBlock(ShikiCodeBlock):
if can_copy: if can_copy:
code = children[0] code = children[0]
copy_button = ( # type: ignore copy_button = (
copy_button copy_button
if copy_button is not None if copy_button is not None
else Button.create( else Button.create(
Icon.create(tag="copy", size=16, color=color("gray", 11)), Icon.create(tag="copy", size=16, color=color("gray", 11)),
on_click=[ on_click=[
set_clipboard(cls._strip_transformer_triggers(code)), # type: ignore set_clipboard(cls._strip_transformer_triggers(code)),
copy_script(), copy_script(),
], ],
style=Style( style=Style(

View File

@ -9,7 +9,7 @@ from reflex.base import Base
from reflex.components.component import Component, ComponentNamespace from reflex.components.component import Component, ComponentNamespace
from reflex.components.markdown.markdown import MarkdownComponentMap from reflex.components.markdown.markdown import MarkdownComponentMap
from reflex.components.props import NoExtrasAllowedProps from reflex.components.props import NoExtrasAllowedProps
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
from reflex.vars.function import FunctionStringVar from reflex.vars.function import FunctionStringVar
@ -928,21 +928,21 @@ class ShikiCodeBlock(Component, MarkdownComponentMap):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ShikiCodeBlock": ) -> "ShikiCodeBlock":
"""Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/). """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
@ -1555,21 +1555,21 @@ class ShikiHighLevelCodeBlock(ShikiCodeBlock):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ShikiHighLevelCodeBlock": ) -> "ShikiHighLevelCodeBlock":
"""Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/). """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
@ -2185,21 +2185,21 @@ class CodeblockNamespace(ComponentNamespace):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "ShikiHighLevelCodeBlock": ) -> "ShikiHighLevelCodeBlock":
"""Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/). """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).

View File

@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Union
from reflex import constants from reflex import constants
from reflex.utils import imports from reflex.utils import imports
from reflex.utils.exceptions import DynamicComponentMissingLibrary from reflex.utils.exceptions import DynamicComponentMissingLibraryError
from reflex.utils.format import format_library_name from reflex.utils.format import format_library_name
from reflex.utils.serializers import serializer from reflex.utils.serializers import serializer
from reflex.vars import Var, get_unique_variable_name from reflex.vars import Var, get_unique_variable_name
@ -36,13 +36,15 @@ def bundle_library(component: Union["Component", str]):
component: The component to bundle the library with. component: The component to bundle the library with.
Raises: Raises:
DynamicComponentMissingLibrary: Raised when a dynamic component is missing a library. DynamicComponentMissingLibraryError: Raised when a dynamic component is missing a library.
""" """
if isinstance(component, str): if isinstance(component, str):
bundled_libraries.add(component) bundled_libraries.add(component)
return return
if component.library is None: if component.library is None:
raise DynamicComponentMissingLibrary("Component must have a library to bundle.") raise DynamicComponentMissingLibraryError(
"Component must have a library to bundle."
)
bundled_libraries.add(format_library_name(component.library)) bundled_libraries.add(format_library_name(component.library))
@ -136,6 +138,23 @@ def load_dynamic_serializer():
module_code_lines.insert(0, "const React = window.__reflex.react;") module_code_lines.insert(0, "const React = window.__reflex.react;")
function_line = next(
index
for index, line in enumerate(module_code_lines)
if line.startswith("export default function")
)
module_code_lines = [
line
for _, line in sorted(
enumerate(module_code_lines),
key=lambda x: (
not (x[1].startswith("import ") and x[0] < function_line),
x[0],
),
)
]
return "\n".join( return "\n".join(
[ [
"//__reflex_evaluate", "//__reflex_evaluate",

View File

@ -48,4 +48,4 @@ PROP_TO_ELEMENTS = {
ELEMENT_TO_PROPS = defaultdict(list) ELEMENT_TO_PROPS = defaultdict(list)
for prop, elements in PROP_TO_ELEMENTS.items(): for prop, elements in PROP_TO_ELEMENTS.items():
for el in elements: for el in elements:
ELEMENT_TO_PROPS[el].append(prop) # type: ignore ELEMENT_TO_PROPS[el].append(prop)

View File

@ -6,7 +6,7 @@ from reflex.components.component import Component
class Element(Component): class Element(Component):
"""The base class for all raw HTML elements.""" """The base class for all raw HTML elements."""
def __eq__(self, other): def __eq__(self, other: object):
"""Two elements are equal if they have the same tag. """Two elements are equal if they have the same tag.
Args: Args:

View File

@ -6,7 +6,7 @@
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -22,21 +22,21 @@ class Element(Component):
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "Element": ) -> "Element":
"""Create the component. """Create the component.

View File

@ -1,58 +1,136 @@
"""Base classes.""" """Base classes."""
from typing import Union from typing import Literal
from reflex.components.el.element import Element from reflex.components.el.element import Element
from reflex.vars.base import Var from reflex.vars.base import Var
AutoCapitalize = Literal["off", "none", "on", "sentences", "words", "characters"]
ContentEditable = Literal[True, False, "inherit", "plaintext-only"]
EnterKeyHint = Literal["enter", "done", "go", "next", "previous", "search", "send"]
InputMode = Literal[
"none", "text", "tel", "url", "email", "numeric", "decimal", "search", "search"
]
AriaRole = Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
]
class BaseHTML(Element): class BaseHTML(Element):
"""Base class for common attributes.""" """Base class for common attributes."""
# Provides a hint for generating a keyboard shortcut for the current element. # Provides a hint for generating a keyboard shortcut for the current element.
access_key: Var[Union[str, int, bool]] access_key: Var[str]
# Controls whether and how text input is automatically capitalized as it is entered/edited by the user. # Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
auto_capitalize: Var[Union[str, int, bool]] auto_capitalize: Var[AutoCapitalize]
# Indicates whether the element's content is editable. # Indicates whether the element's content is editable.
content_editable: Var[Union[str, int, bool]] content_editable: Var[ContentEditable]
# Defines the ID of a <menu> element which will serve as the element's context menu. # Defines the ID of a <menu> element which will serve as the element's context menu.
context_menu: Var[Union[str, int, bool]] context_menu: Var[str]
# Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left) # Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
dir: Var[Union[str, int, bool]] dir: Var[str]
# Defines whether the element can be dragged. # Defines whether the element can be dragged.
draggable: Var[Union[str, int, bool]] draggable: Var[bool]
# Hints what media types the media element is able to play. # Hints what media types the media element is able to play.
enter_key_hint: Var[Union[str, int, bool]] enter_key_hint: Var[EnterKeyHint]
# Defines whether the element is hidden. # Defines whether the element is hidden.
hidden: Var[Union[str, int, bool]] hidden: Var[bool]
# Defines the type of the element. # Defines the type of the element.
input_mode: Var[Union[str, int, bool]] input_mode: Var[InputMode]
# Defines the name of the element for metadata purposes. # Defines the name of the element for metadata purposes.
item_prop: Var[Union[str, int, bool]] item_prop: Var[str]
# Defines the language used in the element. # Defines the language used in the element.
lang: Var[Union[str, int, bool]] lang: Var[str]
# Defines the role of the element. # Defines the role of the element.
role: Var[Union[str, int, bool]] role: Var[AriaRole]
# Assigns a slot in a shadow DOM shadow tree to an element. # Assigns a slot in a shadow DOM shadow tree to an element.
slot: Var[Union[str, int, bool]] slot: Var[str]
# Defines whether the element may be checked for spelling errors. # Defines whether the element may be checked for spelling errors.
spell_check: Var[Union[str, int, bool]] spell_check: Var[bool]
# Defines the position of the current element in the tabbing order. # Defines the position of the current element in the tabbing order.
tab_index: Var[Union[str, int, bool]] tab_index: Var[int]
# Defines a tooltip for the element. # Defines a tooltip for the element.
title: Var[Union[str, int, bool]] title: Var[str]

View File

@ -3,64 +3,323 @@
# ------------------- DO NOT EDIT ---------------------- # ------------------- DO NOT EDIT ----------------------
# This file was generated by `reflex/utils/pyi_generator.py`! # This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------ # ------------------------------------------------------
from typing import Any, Dict, Optional, Union, overload from typing import Any, Dict, Literal, Optional, Union, overload
from reflex.components.el.element import Element from reflex.components.el.element import Element
from reflex.event import BASE_STATE, EventType from reflex.event import EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
AutoCapitalize = Literal["off", "none", "on", "sentences", "words", "characters"]
ContentEditable = Literal[True, False, "inherit", "plaintext-only"]
EnterKeyHint = Literal["enter", "done", "go", "next", "previous", "search", "send"]
InputMode = Literal[
"none", "text", "tel", "url", "email", "numeric", "decimal", "search", "search"
]
AriaRole = Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
]
class BaseHTML(Element): class BaseHTML(Element):
@overload @overload
@classmethod @classmethod
def create( # type: ignore def create( # type: ignore
cls, cls,
*children, *children,
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, access_key: Optional[Union[Var[str], str]] = None,
auto_capitalize: Optional[ auto_capitalize: Optional[
Union[Var[Union[bool, int, str]], bool, int, str] Union[
Literal["characters", "none", "off", "on", "sentences", "words"],
Var[Literal["characters", "none", "off", "on", "sentences", "words"]],
]
] = None, ] = None,
content_editable: Optional[ content_editable: Optional[
Union[Var[Union[bool, int, str]], bool, int, str] Union[
Literal["inherit", "plaintext-only", False, True],
Var[Literal["inherit", "plaintext-only", False, True]],
]
] = None, ] = None,
context_menu: Optional[ context_menu: Optional[Union[Var[str], str]] = None,
Union[Var[Union[bool, int, str]], bool, int, str] dir: Optional[Union[Var[str], str]] = None,
] = None, draggable: Optional[Union[Var[bool], bool]] = None,
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
enter_key_hint: Optional[ enter_key_hint: Optional[
Union[Var[Union[bool, int, str]], bool, int, str] Union[
Literal["done", "enter", "go", "next", "previous", "search", "send"],
Var[
Literal["done", "enter", "go", "next", "previous", "search", "send"]
],
]
] = None, ] = None,
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, hidden: Optional[Union[Var[bool], bool]] = None,
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, input_mode: Optional[
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, Union[
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, Literal[
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "decimal",
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "email",
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "none",
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "numeric",
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, "search",
"tel",
"text",
"url",
],
Var[
Literal[
"decimal",
"email",
"none",
"numeric",
"search",
"tel",
"text",
"url",
]
],
]
] = None,
item_prop: Optional[Union[Var[str], str]] = None,
lang: Optional[Union[Var[str], str]] = None,
role: Optional[
Union[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
],
Var[
Literal[
"alert",
"alertdialog",
"application",
"article",
"banner",
"button",
"cell",
"checkbox",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"dialog",
"directory",
"document",
"feed",
"figure",
"form",
"grid",
"gridcell",
"group",
"heading",
"img",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"navigation",
"none",
"note",
"option",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
]
],
]
] = None,
slot: Optional[Union[Var[str], str]] = None,
spell_check: Optional[Union[Var[bool], bool]] = None,
tab_index: Optional[Union[Var[int], int]] = None,
title: Optional[Union[Var[str], str]] = None,
style: Optional[Style] = None, style: Optional[Style] = None,
key: Optional[Any] = None, key: Optional[Any] = None,
id: Optional[Any] = None, id: Optional[Any] = None,
class_name: Optional[Any] = None, class_name: Optional[Any] = None,
autofocus: Optional[bool] = None, autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None, on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None, on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None, on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None, on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None, on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None, on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None, on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None, on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None, on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None, on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None, on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None, on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None, on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None, on_unmount: Optional[EventType[()]] = None,
**props, **props,
) -> "BaseHTML": ) -> "BaseHTML":
"""Create the component. """Create the component.

View File

@ -3,7 +3,7 @@
from __future__ import annotations from __future__ import annotations
from hashlib import md5 from hashlib import md5
from typing import Any, Dict, Iterator, Set, Tuple, Union from typing import Any, Dict, Iterator, Literal, Set, Tuple, Union
from jinja2 import Environment from jinja2 import Environment
@ -41,6 +41,8 @@ HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
""" """
) )
ButtonType = Literal["submit", "reset", "button"]
class Button(BaseHTML): class Button(BaseHTML):
"""Display the button element.""" """Display the button element."""
@ -48,37 +50,37 @@ class Button(BaseHTML):
tag = "button" tag = "button"
# Automatically focuses the button when the page loads # Automatically focuses the button when the page loads
auto_focus: Var[Union[str, int, bool]] auto_focus: Var[bool]
# Disables the button # Disables the button
disabled: Var[bool] disabled: Var[bool]
# Associates the button with a form (by id) # Associates the button with a form (by id)
form: Var[Union[str, int, bool]] form: Var[str]
# URL to send the form data to (for type="submit" buttons) # URL to send the form data to (for type="submit" buttons)
form_action: Var[Union[str, int, bool]] form_action: Var[str]
# How the form data should be encoded when submitting to the server (for type="submit" buttons) # How the form data should be encoded when submitting to the server (for type="submit" buttons)
form_enc_type: Var[Union[str, int, bool]] form_enc_type: Var[str]
# HTTP method to use for sending form data (for type="submit" buttons) # HTTP method to use for sending form data (for type="submit" buttons)
form_method: Var[Union[str, int, bool]] form_method: Var[str]
# Bypasses form validation when submitting (for type="submit" buttons) # Bypasses form validation when submitting (for type="submit" buttons)
form_no_validate: Var[Union[str, int, bool]] form_no_validate: Var[bool]
# Specifies where to display the response after submitting the form (for type="submit" buttons) # Specifies where to display the response after submitting the form (for type="submit" buttons)
form_target: Var[Union[str, int, bool]] form_target: Var[str]
# Name of the button, used when sending form data # Name of the button, used when sending form data
name: Var[Union[str, int, bool]] name: Var[str]
# Type of the button (submit, reset, or button) # Type of the button (submit, reset, or button)
type: Var[Union[str, int, bool]] type: Var[ButtonType]
# Value of the button, used when sending form data # Value of the button, used when sending form data
value: Var[Union[str, int, bool]] value: Var[Union[str, int, float]]
class Datalist(BaseHTML): class Datalist(BaseHTML):
@ -93,16 +95,16 @@ class Fieldset(Element):
tag = "fieldset" tag = "fieldset"
# Disables all the form control descendants of the fieldset # Disables all the form control descendants of the fieldset
disabled: Var[Union[str, int, bool]] disabled: Var[bool]
# Associates the fieldset with a form (by id) # Associates the fieldset with a form (by id)
form: Var[Union[str, int, bool]] form: Var[str]
# Name of the fieldset, used for scripting # Name of the fieldset, used for scripting
name: Var[Union[str, int, bool]] name: Var[str]
def on_submit_event_spec() -> Tuple[Var[Dict[str, Any]]]: def on_submit_event_spec() -> Tuple[Var[dict[str, Any]]]:
"""Event handler spec for the on_submit event. """Event handler spec for the on_submit event.
Returns: Returns:
@ -111,7 +113,7 @@ def on_submit_event_spec() -> Tuple[Var[Dict[str, Any]]]:
return (FORM_DATA,) return (FORM_DATA,)
def on_submit_string_event_spec() -> Tuple[Var[Dict[str, str]]]: def on_submit_string_event_spec() -> Tuple[Var[dict[str, str]]]:
"""Event handler spec for the on_submit event. """Event handler spec for the on_submit event.
Returns: Returns:
@ -126,34 +128,34 @@ class Form(BaseHTML):
tag = "form" tag = "form"
# MIME types the server accepts for file upload # MIME types the server accepts for file upload
accept: Var[Union[str, int, bool]] accept: Var[str]
# Character encodings to be used for form submission # Character encodings to be used for form submission
accept_charset: Var[Union[str, int, bool]] accept_charset: Var[str]
# URL where the form's data should be submitted # URL where the form's data should be submitted
action: Var[Union[str, int, bool]] action: Var[str]
# Whether the form should have autocomplete enabled # Whether the form should have autocomplete enabled
auto_complete: Var[Union[str, int, bool]] auto_complete: Var[str]
# Encoding type for the form data when submitted # Encoding type for the form data when submitted
enc_type: Var[Union[str, int, bool]] enc_type: Var[str]
# HTTP method to use for form submission # HTTP method to use for form submission
method: Var[Union[str, int, bool]] method: Var[str]
# Name of the form # Name of the form
name: Var[Union[str, int, bool]] name: Var[str]
# Indicates that the form should not be validated on submit # Indicates that the form should not be validated on submit
no_validate: Var[Union[str, int, bool]] no_validate: Var[bool]
# Where to display the response after submitting the form # Where to display the response after submitting the form
target: Var[Union[str, int, bool]] target: Var[str]
# If true, the form will be cleared after submit. # If true, the form will be cleared after submit.
reset_on_submit: Var[bool] = False # type: ignore reset_on_submit: Var[bool] = Var.create(False)
# The name used to make this form's submit handler function unique. # The name used to make this form's submit handler function unique.
handle_submit_unique_name: Var[str] handle_submit_unique_name: Var[str]
@ -266,106 +268,126 @@ class Form(BaseHTML):
] ]
HTMLInputTypeAttribute = Literal[
"button",
"checkbox",
"color",
"date",
"datetime-local",
"email",
"file",
"hidden",
"image",
"month",
"number",
"password",
"radio",
"range",
"reset",
"search",
"submit",
"tel",
"text",
"time",
"url",
"week",
]
class Input(BaseHTML): class Input(BaseHTML):
"""Display the input element.""" """Display the input element."""
tag = "input" tag = "input"
# Accepted types of files when the input is file type # Accepted types of files when the input is file type
accept: Var[Union[str, int, bool]] accept: Var[str]
# Alternate text for input type="image" # Alternate text for input type="image"
alt: Var[Union[str, int, bool]] alt: Var[str]
# Whether the input should have autocomplete enabled # Whether the input should have autocomplete enabled
auto_complete: Var[Union[str, int, bool]] auto_complete: Var[str]
# Automatically focuses the input when the page loads # Automatically focuses the input when the page loads
auto_focus: Var[Union[str, int, bool]] auto_focus: Var[bool]
# Captures media from the user (camera or microphone) # Captures media from the user (camera or microphone)
capture: Var[Union[str, int, bool]] capture: Var[Literal[True, False, "user", "environment"]]
# Indicates whether the input is checked (for checkboxes and radio buttons) # Indicates whether the input is checked (for checkboxes and radio buttons)
checked: Var[Union[str, int, bool]] checked: Var[bool]
# The initial value (for checkboxes and radio buttons) # The initial value (for checkboxes and radio buttons)
default_checked: Var[bool] default_checked: Var[bool]
# The initial value for a text field # The initial value for a text field
default_value: Var[str] default_value: Var[Union[str, int, float]]
# Name part of the input to submit in 'dir' and 'name' pair when form is submitted
dirname: Var[Union[str, int, bool]]
# Disables the input # Disables the input
disabled: Var[Union[str, int, bool]] disabled: Var[bool]
# Associates the input with a form (by id) # Associates the input with a form (by id)
form: Var[Union[str, int, bool]] form: Var[str]
# URL to send the form data to (for type="submit" buttons) # URL to send the form data to (for type="submit" buttons)
form_action: Var[Union[str, int, bool]] form_action: Var[str]
# How the form data should be encoded when submitting to the server (for type="submit" buttons) # How the form data should be encoded when submitting to the server (for type="submit" buttons)
form_enc_type: Var[Union[str, int, bool]] form_enc_type: Var[str]
# HTTP method to use for sending form data (for type="submit" buttons) # HTTP method to use for sending form data (for type="submit" buttons)
form_method: Var[Union[str, int, bool]] form_method: Var[str]
# Bypasses form validation when submitting (for type="submit" buttons) # Bypasses form validation when submitting (for type="submit" buttons)
form_no_validate: Var[Union[str, int, bool]] form_no_validate: Var[bool]
# Specifies where to display the response after submitting the form (for type="submit" buttons) # Specifies where to display the response after submitting the form (for type="submit" buttons)
form_target: Var[Union[str, int, bool]] form_target: Var[str]
# References a datalist for suggested options # References a datalist for suggested options
list: Var[Union[str, int, bool]] list: Var[str]
# Specifies the maximum value for the input # Specifies the maximum value for the input
max: Var[Union[str, int, bool]] max: Var[Union[str, int, float]]
# Specifies the maximum number of characters allowed in the input # Specifies the maximum number of characters allowed in the input
max_length: Var[Union[str, int, bool]] max_length: Var[Union[int, float]]
# Specifies the minimum number of characters required in the input # Specifies the minimum number of characters required in the input
min_length: Var[Union[str, int, bool]] min_length: Var[Union[int, float]]
# Specifies the minimum value for the input # Specifies the minimum value for the input
min: Var[Union[str, int, bool]] min: Var[Union[str, int, float]]
# Indicates whether multiple values can be entered in an input of the type email or file # Indicates whether multiple values can be entered in an input of the type email or file
multiple: Var[Union[str, int, bool]] multiple: Var[bool]
# Name of the input, used when sending form data # Name of the input, used when sending form data
name: Var[Union[str, int, bool]] name: Var[str]
# Regex pattern the input's value must match to be valid # Regex pattern the input's value must match to be valid
pattern: Var[Union[str, int, bool]] pattern: Var[str]
# Placeholder text in the input # Placeholder text in the input
placeholder: Var[Union[str, int, bool]] placeholder: Var[str]
# Indicates whether the input is read-only # Indicates whether the input is read-only
read_only: Var[Union[str, int, bool]] read_only: Var[bool]
# Indicates that the input is required # Indicates that the input is required
required: Var[Union[str, int, bool]] required: Var[bool]
# Specifies the visible width of a text control # Specifies the visible width of a text control
size: Var[Union[str, int, bool]] size: Var[Union[int, float]]
# URL for image inputs # URL for image inputs
src: Var[Union[str, int, bool]] src: Var[str]
# Specifies the legal number intervals for an input # Specifies the legal number intervals for an input
step: Var[Union[str, int, bool]] step: Var[Union[str, int, float]]
# Specifies the type of input # Specifies the type of input
type: Var[Union[str, int, bool]] type: Var[HTMLInputTypeAttribute]
# Name of the image map used with the input
use_map: Var[Union[str, int, bool]]
# Value of the input # Value of the input
value: Var[Union[str, int, float]] value: Var[Union[str, int, float]]
@ -405,7 +427,7 @@ class Input(BaseHTML):
(value_var := Var.create(value))._var_type (value_var := Var.create(value))._var_type
): ):
props["value"] = ternary_operation( props["value"] = ternary_operation(
(value_var != Var.create(None)) # pyright: ignore [reportGeneralTypeIssues] (value_var != Var.create(None)) # pyright: ignore [reportArgumentType]
& (value_var != Var(_js_expr="undefined")), & (value_var != Var(_js_expr="undefined")),
value, value,
Var.create(""), Var.create(""),
@ -419,10 +441,10 @@ class Label(BaseHTML):
tag = "label" tag = "label"
# ID of a form control with which the label is associated # ID of a form control with which the label is associated
html_for: Var[Union[str, int, bool]] html_for: Var[str]
# Associates the label with a form (by id) # Associates the label with a form (by id)
form: Var[Union[str, int, bool]] form: Var[str]
class Legend(BaseHTML): class Legend(BaseHTML):
@ -437,25 +459,25 @@ class Meter(BaseHTML):
tag = "meter" tag = "meter"
# Associates the meter with a form (by id) # Associates the meter with a form (by id)
form: Var[Union[str, int, bool]] form: Var[str]
# High limit of range (above this is considered high value) # High limit of range (above this is considered high value)
high: Var[Union[str, int, bool]] high: Var[Union[int, float]]
# Low limit of range (below this is considered low value) # Low limit of range (below this is considered low value)
low: Var[Union[str, int, bool]] low: Var[Union[int, float]]
# Maximum value of the range # Maximum value of the range
max: Var[Union[str, int, bool]] max: Var[Union[int, float]]
# Minimum value of the range # Minimum value of the range
min: Var[Union[str, int, bool]] min: Var[Union[int, float]]
# Optimum value in the range # Optimum value in the range
optimum: Var[Union[str, int, bool]] optimum: Var[Union[int, float]]
# Current value of the meter # Current value of the meter
value: Var[Union[str, int, bool]] value: Var[Union[int, float]]
class Optgroup(BaseHTML): class Optgroup(BaseHTML):
@ -464,10 +486,10 @@ class Optgroup(BaseHTML):
tag = "optgroup" tag = "optgroup"
# Disables the optgroup # Disables the optgroup
disabled: Var[Union[str, int, bool]] disabled: Var[bool]
# Label for the optgroup # Label for the optgroup
label: Var[Union[str, int, bool]] label: Var[str]
class Option(BaseHTML): class Option(BaseHTML):
@ -476,16 +498,16 @@ class Option(BaseHTML):
tag = "option" tag = "option"
# Disables the option # Disables the option
disabled: Var[Union[str, int, bool]] disabled: Var[bool]
# Label for the option, if the text is not the label # Label for the option, if the text is not the label
label: Var[Union[str, int, bool]] label: Var[str]
# Indicates that the option is initially selected # Indicates that the option is initially selected
selected: Var[Union[str, int, bool]] selected: Var[bool]
# Value to be sent as form data # Value to be sent as form data
value: Var[Union[str, int, bool]] value: Var[Union[str, int, float]]
class Output(BaseHTML): class Output(BaseHTML):
@ -494,13 +516,13 @@ class Output(BaseHTML):
tag = "output" tag = "output"
# Associates the output with one or more elements (by their IDs) # Associates the output with one or more elements (by their IDs)
html_for: Var[Union[str, int, bool]] html_for: Var[str]
# Associates the output with a form (by id) # Associates the output with a form (by id)
form: Var[Union[str, int, bool]] form: Var[str]
# Name of the output element for form submission # Name of the output element for form submission
name: Var[Union[str, int, bool]] name: Var[str]
class Progress(BaseHTML): class Progress(BaseHTML):
@ -509,13 +531,13 @@ class Progress(BaseHTML):
tag = "progress" tag = "progress"
# Associates the progress element with a form (by id) # Associates the progress element with a form (by id)
form: Var[Union[str, int, bool]] form: Var[str]
# Maximum value of the progress indicator # Maximum value of the progress indicator
max: Var[Union[str, int, bool]] max: Var[Union[str, int, float]]
# Current value of the progress indicator # Current value of the progress indicator
value: Var[Union[str, int, bool]] value: Var[Union[str, int, float]]
class Select(BaseHTML): class Select(BaseHTML):
@ -524,28 +546,28 @@ class Select(BaseHTML):
tag = "select" tag = "select"
# Whether the form control should have autocomplete enabled # Whether the form control should have autocomplete enabled
auto_complete: Var[Union[str, int, bool]] auto_complete: Var[str]
# Automatically focuses the select when the page loads # Automatically focuses the select when the page loads
auto_focus: Var[Union[str, int, bool]] auto_focus: Var[bool]
# Disables the select control # Disables the select control
disabled: Var[Union[str, int, bool]] disabled: Var[bool]
# Associates the select with a form (by id) # Associates the select with a form (by id)
form: Var[Union[str, int, bool]] form: Var[str]
# Indicates that multiple options can be selected # Indicates that multiple options can be selected
multiple: Var[Union[str, int, bool]] multiple: Var[bool]
# Name of the select, used when submitting the form # Name of the select, used when submitting the form
name: Var[Union[str, int, bool]] name: Var[str]
# Indicates that the select control must have a selected option # Indicates that the select control must have a selected option
required: Var[Union[str, int, bool]] required: Var[bool]
# Number of visible options in a drop-down list # Number of visible options in a drop-down list
size: Var[Union[str, int, bool]] size: Var[int]
# Fired when the select value changes # Fired when the select value changes
on_change: EventHandler[input_event] on_change: EventHandler[input_event]
@ -587,58 +609,58 @@ class Textarea(BaseHTML):
tag = "textarea" tag = "textarea"
# Whether the form control should have autocomplete enabled # Whether the form control should have autocomplete enabled
auto_complete: Var[Union[str, int, bool]] auto_complete: Var[str]
# Automatically focuses the textarea when the page loads # Automatically focuses the textarea when the page loads
auto_focus: Var[Union[str, int, bool]] auto_focus: Var[bool]
# Automatically fit the content height to the text (use min-height with this prop) # Automatically fit the content height to the text (use min-height with this prop)
auto_height: Var[bool] auto_height: Var[bool]
# Visible width of the text control, in average character widths # Visible width of the text control, in average character widths
cols: Var[Union[str, int, bool]] cols: Var[int]
# The default value of the textarea when initially rendered # The default value of the textarea when initially rendered
default_value: Var[str] default_value: Var[str]
# Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted # Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted
dirname: Var[Union[str, int, bool]] dirname: Var[str]
# Disables the textarea # Disables the textarea
disabled: Var[Union[str, int, bool]] disabled: Var[bool]
# Enter key submits form (shift-enter adds new line) # Enter key submits form (shift-enter adds new line)
enter_key_submit: Var[bool] enter_key_submit: Var[bool]
# Associates the textarea with a form (by id) # Associates the textarea with a form (by id)
form: Var[Union[str, int, bool]] form: Var[str]
# Maximum number of characters allowed in the textarea # Maximum number of characters allowed in the textarea
max_length: Var[Union[str, int, bool]] max_length: Var[int]
# Minimum number of characters required in the textarea # Minimum number of characters required in the textarea
min_length: Var[Union[str, int, bool]] min_length: Var[int]
# Name of the textarea, used when submitting the form # Name of the textarea, used when submitting the form
name: Var[Union[str, int, bool]] name: Var[str]
# Placeholder text in the textarea # Placeholder text in the textarea
placeholder: Var[Union[str, int, bool]] placeholder: Var[str]
# Indicates whether the textarea is read-only # Indicates whether the textarea is read-only
read_only: Var[Union[str, int, bool]] read_only: Var[bool]
# Indicates that the textarea is required # Indicates that the textarea is required
required: Var[Union[str, int, bool]] required: Var[bool]
# Visible number of lines in the text control # Visible number of lines in the text control
rows: Var[Union[str, int, bool]] rows: Var[int]
# The controlled value of the textarea, read only unless used with on_change # The controlled value of the textarea, read only unless used with on_change
value: Var[Union[str, int, bool]] value: Var[str]
# How the text in the textarea is to be wrapped when submitting the form # How the text in the textarea is to be wrapped when submitting the form
wrap: Var[Union[str, int, bool]] wrap: Var[str]
# Fired when the input value changes # Fired when the input value changes
on_change: EventHandler[input_event] on_change: EventHandler[input_event]

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,23 @@
"""Inline classes.""" """Inline classes."""
from typing import Union from typing import Literal, Union
from reflex.vars.base import Var from reflex.vars.base import Var
from .base import BaseHTML from .base import BaseHTML
ReferrerPolicy = Literal[
"",
"no-referrer",
"no-referrer-when-downgrade",
"origin",
"origin-when-cross-origin",
"same-origin",
"strict-origin",
"strict-origin-when-cross-origin",
"unsafe-url",
]
class A(BaseHTML): # Inherits common attributes from BaseMeta class A(BaseHTML): # Inherits common attributes from BaseMeta
"""Display the 'a' element.""" """Display the 'a' element."""
@ -13,31 +25,28 @@ class A(BaseHTML): # Inherits common attributes from BaseMeta
tag = "a" tag = "a"
# Specifies that the target (the file specified in the href attribute) will be downloaded when a user clicks on the hyperlink. # Specifies that the target (the file specified in the href attribute) will be downloaded when a user clicks on the hyperlink.
download: Var[Union[str, int, bool]] download: Var[Union[str, bool]]
# Specifies the URL of the page the link goes to # Specifies the URL of the page the link goes to
href: Var[Union[str, int, bool]] href: Var[str]
# Specifies the language of the linked document # Specifies the language of the linked document
href_lang: Var[Union[str, int, bool]] href_lang: Var[str]
# Specifies what media/device the linked document is optimized for # Specifies what media/device the linked document is optimized for
media: Var[Union[str, int, bool]] media: Var[str]
# Specifies which referrer is sent when fetching the resource # Specifies which referrer is sent when fetching the resource
ping: Var[Union[str, int, bool]] ping: Var[str]
# Specifies the relationship between the current document and the linked document # Specifies the relationship between the current document and the linked document
referrer_policy: Var[Union[str, int, bool]] referrer_policy: Var[ReferrerPolicy]
# Specifies the relationship between the linked document and the current document # Specifies the relationship between the linked document and the current document
rel: Var[Union[str, int, bool]] rel: Var[str]
# Specifies the shape of the area
shape: Var[Union[str, int, bool]]
# Specifies where to open the linked document # Specifies where to open the linked document
target: Var[Union[str, int, bool]] target: Var[Union[str, Literal["_self", "_blank", "_parent", "_top"]]]
class Abbr(BaseHTML): class Abbr(BaseHTML):
@ -88,7 +97,7 @@ class Data(BaseHTML):
tag = "data" tag = "data"
# Specifies the machine-readable translation of the data element. # Specifies the machine-readable translation of the data element.
value: Var[Union[str, int, bool]] value: Var[Union[str, int, float]]
class Dfn(BaseHTML): class Dfn(BaseHTML):
@ -127,7 +136,7 @@ class Q(BaseHTML):
tag = "q" tag = "q"
# Specifies the source URL of the quote. # Specifies the source URL of the quote.
cite: Var[Union[str, int, bool]] cite: Var[str]
class Rp(BaseHTML): class Rp(BaseHTML):
@ -196,7 +205,7 @@ class Time(BaseHTML):
tag = "time" tag = "time"
# Specifies the date and/or time of the element. # Specifies the date and/or time of the element.
date_time: Var[Union[str, int, bool]] date_time: Var[str]
class U(BaseHTML): class U(BaseHTML):

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
"""Media classes.""" """Media classes."""
from typing import Any, Union from typing import Any, Literal, Union
from reflex import Component, ComponentNamespace from reflex import Component, ComponentNamespace
from reflex.components.el.elements.inline import ReferrerPolicy
from reflex.constants.colors import Color from reflex.constants.colors import Color
from reflex.vars.base import Var from reflex.vars.base import Var
@ -15,37 +16,37 @@ class Area(BaseHTML):
tag = "area" tag = "area"
# Alternate text for the area, used for accessibility # Alternate text for the area, used for accessibility
alt: Var[Union[str, int, bool]] alt: Var[str]
# Coordinates to define the shape of the area # Coordinates to define the shape of the area
coords: Var[Union[str, int, bool]] coords: Var[str]
# Specifies that the target will be downloaded when clicked # Specifies that the target will be downloaded when clicked
download: Var[Union[str, int, bool]] download: Var[Union[str, bool]]
# Hyperlink reference for the area # Hyperlink reference for the area
href: Var[Union[str, int, bool]] href: Var[str]
# Language of the linked resource # Language of the linked resource
href_lang: Var[Union[str, int, bool]] href_lang: Var[str]
# Specifies what media/device the linked resource is optimized for # Specifies what media/device the linked resource is optimized for
media: Var[Union[str, int, bool]] media: Var[str]
# A list of URLs to be notified if the user follows the hyperlink
ping: Var[Union[str, int, bool]]
# Specifies which referrer information to send with the link # Specifies which referrer information to send with the link
referrer_policy: Var[Union[str, int, bool]] referrer_policy: Var[ReferrerPolicy]
# Specifies the relationship of the target object to the link object # Specifies the relationship of the target object to the link object
rel: Var[Union[str, int, bool]] rel: Var[str]
# Defines the shape of the area (rectangle, circle, polygon) # Defines the shape of the area (rectangle, circle, polygon)
shape: Var[Union[str, int, bool]] shape: Var[str]
# Specifies where to open the linked document # Specifies where to open the linked document
target: Var[Union[str, int, bool]] target: Var[str]
CrossOrigin = Literal["anonymous", "use-credentials", ""]
class Audio(BaseHTML): class Audio(BaseHTML):
@ -54,28 +55,29 @@ class Audio(BaseHTML):
tag = "audio" tag = "audio"
# Specifies that the audio will start playing as soon as it is ready # Specifies that the audio will start playing as soon as it is ready
auto_play: Var[Union[str, int, bool]] auto_play: Var[bool]
# Represents the time range of the buffered media
buffered: Var[Union[str, int, bool]]
# Displays the standard audio controls # Displays the standard audio controls
controls: Var[Union[str, int, bool]] controls: Var[bool]
# Configures the CORS requests for the element # Configures the CORS requests for the element
cross_origin: Var[Union[str, int, bool]] cross_origin: Var[CrossOrigin]
# Specifies that the audio will loop # Specifies that the audio will loop
loop: Var[Union[str, int, bool]] loop: Var[bool]
# Indicates whether the audio is muted by default # Indicates whether the audio is muted by default
muted: Var[Union[str, int, bool]] muted: Var[bool]
# Specifies how the audio file should be preloaded # Specifies how the audio file should be preloaded
preload: Var[Union[str, int, bool]] preload: Var[str]
# URL of the audio to play # URL of the audio to play
src: Var[Union[str, int, bool]] src: Var[str]
ImageDecoding = Literal["async", "auto", "sync"]
ImageLoading = Literal["eager", "lazy"]
class Img(BaseHTML): class Img(BaseHTML):
@ -83,41 +85,32 @@ class Img(BaseHTML):
tag = "img" tag = "img"
# Image alignment with respect to its surrounding elements
align: Var[Union[str, int, bool]]
# Alternative text for the image # Alternative text for the image
alt: Var[Union[str, int, bool]] alt: Var[str]
# Configures the CORS requests for the image # Configures the CORS requests for the image
cross_origin: Var[Union[str, int, bool]] cross_origin: Var[CrossOrigin]
# How the image should be decoded # How the image should be decoded
decoding: Var[Union[str, int, bool]] decoding: Var[ImageDecoding]
# Specifies an intrinsic size for the image
intrinsicsize: Var[Union[str, int, bool]]
# Whether the image is a server-side image map
ismap: Var[Union[str, int, bool]]
# Specifies the loading behavior of the image # Specifies the loading behavior of the image
loading: Var[Union[str, int, bool]] loading: Var[ImageLoading]
# Referrer policy for the image # Referrer policy for the image
referrer_policy: Var[Union[str, int, bool]] referrer_policy: Var[ReferrerPolicy]
# Sizes of the image for different layouts # Sizes of the image for different layouts
sizes: Var[Union[str, int, bool]] sizes: Var[str]
# URL of the image to display # URL of the image to display
src: Var[Any] src: Var[Any]
# A set of source sizes and URLs for responsive images # A set of source sizes and URLs for responsive images
src_set: Var[Union[str, int, bool]] src_set: Var[str]
# The name of the map to use with the image # The name of the map to use with the image
use_map: Var[Union[str, int, bool]] use_map: Var[str]
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children, **props) -> Component:
@ -143,7 +136,7 @@ class Map(BaseHTML):
tag = "map" tag = "map"
# Name of the map, referenced by the 'usemap' attribute in 'img' and 'object' elements # Name of the map, referenced by the 'usemap' attribute in 'img' and 'object' elements
name: Var[Union[str, int, bool]] name: Var[str]
class Track(BaseHTML): class Track(BaseHTML):
@ -152,19 +145,19 @@ class Track(BaseHTML):
tag = "track" tag = "track"
# Indicates that the track should be enabled unless the user's preferences indicate otherwise # Indicates that the track should be enabled unless the user's preferences indicate otherwise
default: Var[Union[str, int, bool]] default: Var[bool]
# Specifies the kind of text track # Specifies the kind of text track
kind: Var[Union[str, int, bool]] kind: Var[str]
# Title of the text track, used by the browser when listing available text tracks # Title of the text track, used by the browser when listing available text tracks
label: Var[Union[str, int, bool]] label: Var[str]
# URL of the track file # URL of the track file
src: Var[Union[str, int, bool]] src: Var[str]
# Language of the track text data # Language of the track text data
src_lang: Var[Union[str, int, bool]] src_lang: Var[str]
class Video(BaseHTML): class Video(BaseHTML):
@ -173,34 +166,31 @@ class Video(BaseHTML):
tag = "video" tag = "video"
# Specifies that the video will start playing as soon as it is ready # Specifies that the video will start playing as soon as it is ready
auto_play: Var[Union[str, int, bool]] auto_play: Var[bool]
# Represents the time range of the buffered media
buffered: Var[Union[str, int, bool]]
# Displays the standard video controls # Displays the standard video controls
controls: Var[Union[str, int, bool]] controls: Var[bool]
# Configures the CORS requests for the video # Configures the CORS requests for the video
cross_origin: Var[Union[str, int, bool]] cross_origin: Var[CrossOrigin]
# Specifies that the video will loop # Specifies that the video will loop
loop: Var[Union[str, int, bool]] loop: Var[bool]
# Indicates whether the video is muted by default # Indicates whether the video is muted by default
muted: Var[Union[str, int, bool]] muted: Var[bool]
# Indicates that the video should play 'inline', inside its element's playback area # Indicates that the video should play 'inline', inside its element's playback area
plays_inline: Var[Union[str, int, bool]] plays_inline: Var[bool]
# URL of an image to show while the video is downloading, or until the user hits the play button # URL of an image to show while the video is downloading, or until the user hits the play button
poster: Var[Union[str, int, bool]] poster: Var[str]
# Specifies how the video file should be preloaded # Specifies how the video file should be preloaded
preload: Var[Union[str, int, bool]] preload: Var[str]
# URL of the video to play # URL of the video to play
src: Var[Union[str, int, bool]] src: Var[str]
class Embed(BaseHTML): class Embed(BaseHTML):
@ -209,10 +199,10 @@ class Embed(BaseHTML):
tag = "embed" tag = "embed"
# URL of the embedded content # URL of the embedded content
src: Var[Union[str, int, bool]] src: Var[str]
# Media type of the embedded content # Media type of the embedded content
type: Var[Union[str, int, bool]] type: Var[str]
class Iframe(BaseHTML): class Iframe(BaseHTML):
@ -220,32 +210,26 @@ class Iframe(BaseHTML):
tag = "iframe" tag = "iframe"
# Alignment of the iframe within the page or surrounding elements
align: Var[Union[str, int, bool]]
# Permissions policy for the iframe # Permissions policy for the iframe
allow: Var[Union[str, int, bool]] allow: Var[str]
# Content Security Policy to apply to the iframe's content
csp: Var[Union[str, int, bool]]
# Specifies the loading behavior of the iframe # Specifies the loading behavior of the iframe
loading: Var[Union[str, int, bool]] loading: Var[Literal["eager", "lazy"]]
# Name of the iframe, used as a target for hyperlinks and forms # Name of the iframe, used as a target for hyperlinks and forms
name: Var[Union[str, int, bool]] name: Var[str]
# Referrer policy for the iframe # Referrer policy for the iframe
referrer_policy: Var[Union[str, int, bool]] referrer_policy: Var[ReferrerPolicy]
# Security restrictions for the content in the iframe # Security restrictions for the content in the iframe
sandbox: Var[Union[str, int, bool]] sandbox: Var[str]
# URL of the document to display in the iframe # URL of the document to display in the iframe
src: Var[Union[str, int, bool]] src: Var[str]
# HTML content to embed directly within the iframe # HTML content to embed directly within the iframe
src_doc: Var[Union[str, int, bool]] src_doc: Var[str]
class Object(BaseHTML): class Object(BaseHTML):
@ -254,19 +238,19 @@ class Object(BaseHTML):
tag = "object" tag = "object"
# URL of the data to be used by the object # URL of the data to be used by the object
data: Var[Union[str, int, bool]] data: Var[str]
# Associates the object with a form element # Associates the object with a form element
form: Var[Union[str, int, bool]] form: Var[str]
# Name of the object, used for scripting or as a target for forms and links # Name of the object, used for scripting or as a target for forms and links
name: Var[Union[str, int, bool]] name: Var[str]
# Media type of the data specified in the data attribute # Media type of the data specified in the data attribute
type: Var[Union[str, int, bool]] type: Var[str]
# Name of an image map to use with the object # Name of an image map to use with the object
use_map: Var[Union[str, int, bool]] use_map: Var[str]
class Picture(BaseHTML): class Picture(BaseHTML):
@ -287,19 +271,19 @@ class Source(BaseHTML):
tag = "source" tag = "source"
# Media query indicating what device the linked resource is optimized for # Media query indicating what device the linked resource is optimized for
media: Var[Union[str, int, bool]] media: Var[str]
# Sizes of the source for different layouts # Sizes of the source for different layouts
sizes: Var[Union[str, int, bool]] sizes: Var[str]
# URL of the media file or an image for the element to use # URL of the media file or an image for the element to use
src: Var[Union[str, int, bool]] src: Var[str]
# A set of source sizes and URLs for responsive images # A set of source sizes and URLs for responsive images
src_set: Var[Union[str, int, bool]] src_set: Var[str]
# Media type of the source # Media type of the source
type: Var[Union[str, int, bool]] type: Var[str]
class Svg(BaseHTML): class Svg(BaseHTML):
@ -431,16 +415,16 @@ class LinearGradient(BaseHTML):
spread_method: Var[Union[str, bool]] spread_method: Var[Union[str, bool]]
# X coordinate of the starting point of the gradient. # X coordinate of the starting point of the gradient.
x1: Var[Union[str, int, bool]] x1: Var[Union[str, int, float]]
# X coordinate of the ending point of the gradient. # X coordinate of the ending point of the gradient.
x2: Var[Union[str, int, bool]] x2: Var[Union[str, int, float]]
# Y coordinate of the starting point of the gradient. # Y coordinate of the starting point of the gradient.
y1: Var[Union[str, int, bool]] y1: Var[Union[str, int, float]]
# Y coordinate of the ending point of the gradient. # Y coordinate of the ending point of the gradient.
y2: Var[Union[str, int, bool]] y2: Var[Union[str, int, float]]
class RadialGradient(BaseHTML): class RadialGradient(BaseHTML):
@ -449,19 +433,19 @@ class RadialGradient(BaseHTML):
tag = "radialGradient" tag = "radialGradient"
# The x coordinate of the end circle of the radial gradient. # The x coordinate of the end circle of the radial gradient.
cx: Var[Union[str, int, bool]] cx: Var[Union[str, int, float]]
# The y coordinate of the end circle of the radial gradient. # The y coordinate of the end circle of the radial gradient.
cy: Var[Union[str, int, bool]] cy: Var[Union[str, int, float]]
# The radius of the start circle of the radial gradient. # The radius of the start circle of the radial gradient.
fr: Var[Union[str, int, bool]] fr: Var[Union[str, int, float]]
# The x coordinate of the start circle of the radial gradient. # The x coordinate of the start circle of the radial gradient.
fx: Var[Union[str, int, bool]] fx: Var[Union[str, int, float]]
# The y coordinate of the start circle of the radial gradient. # The y coordinate of the start circle of the radial gradient.
fy: Var[Union[str, int, bool]] fy: Var[Union[str, int, float]]
# Units for the gradient. # Units for the gradient.
gradient_units: Var[Union[str, bool]] gradient_units: Var[Union[str, bool]]
@ -470,7 +454,7 @@ class RadialGradient(BaseHTML):
gradient_transform: Var[Union[str, bool]] gradient_transform: Var[Union[str, bool]]
# The radius of the end circle of the radial gradient. # The radius of the end circle of the radial gradient.
r: Var[Union[str, int, bool]] r: Var[Union[str, int, float]]
# Method used to spread the gradient. # Method used to spread the gradient.
spread_method: Var[Union[str, bool]] spread_method: Var[Union[str, bool]]
@ -497,7 +481,7 @@ class Path(BaseHTML):
tag = "path" tag = "path"
# Defines the shape of the path. # Defines the shape of the path.
d: Var[Union[str, int, bool]] d: Var[Union[str, int, float]]
class SVG(ComponentNamespace): class SVG(ComponentNamespace):

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More