Merge remote-tracking branch 'origin/main' into include_step_attribute_in_input

This commit is contained in:
Masen Furer 2024-12-13 10:59:31 -08:00
commit 1c70fab11a
No known key found for this signature in database
GPG Key ID: B0008AD22B3B3A95
377 changed files with 27010 additions and 21521 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
@reflex-dev/reflex-team

View File

@ -2,7 +2,6 @@
name: Bug report name: Bug report
about: Create a report to help us improve about: Create a report to help us improve
title: '' title: ''
labels: bug
assignees: '' assignees: ''
--- ---

View File

@ -0,0 +1,19 @@
---
name: Enhancement Request
about: Suggest an enhancement for an existing Reflex feature.
title: ''
labels: 'enhancement'
assignees: ''
---
**Describe the Enhancement you want**
A clear and concise description of what the improvement does.
- Which feature do you want to improve? (and what problem does it have)
- What is the benefit of the enhancement?
- Show an example/usecase were the improvement are needed.
**Additional context**
Add any other context here.

View File

@ -0,0 +1,18 @@
---
name: Feature Request
about: Suggest a new feature for Reflex
title: ''
labels: 'feature request'
assignees: ''
---
**Describe the Features**
A clear and concise description of what the features does.
- What is the purpose of the feature?
- Show an example / use cases for the new feature.
**Additional context**
Add any other context here.

View File

@ -18,7 +18,7 @@ inputs:
poetry-version: poetry-version:
description: 'Poetry version to install' description: 'Poetry version to install'
required: false required: false
default: '1.3.1' default: '1.8.3'
run-poetry-install: run-poetry-install:
description: 'Whether to run poetry install on current dir' description: 'Whether to run poetry install on current dir'
required: false required: false

View File

@ -80,7 +80,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
# Show OS combos first in GUI # Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-12] os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0'] python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
exclude: exclude:
- os: windows-latest - os: windows-latest
@ -92,7 +92,7 @@ jobs:
python-version: '3.9.18' python-version: '3.9.18'
- os: macos-latest - os: macos-latest
python-version: '3.10.13' python-version: '3.10.13'
- os: macos-12 - os: macos-latest
python-version: '3.12.0' python-version: '3.12.0'
include: include:
- os: windows-latest - os: windows-latest
@ -155,7 +155,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
# Show OS combos first in GUI # Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-12] os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.11.5'] python-version: ['3.11.5']
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}

View File

@ -14,11 +14,14 @@ env:
jobs: jobs:
check_latest_node: check_latest_node:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
strategy: strategy:
matrix: matrix:
python-version: ['3.12'] python-version: ['3.12']
split_index: [1, 2]
node-version: ['node'] node-version: ['node']
fail-fast: false
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env - uses: ./.github/actions/setup_build_env
@ -30,11 +33,11 @@ jobs:
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- run: | - run: |
poetry run uv pip install pyvirtualdisplay pillow poetry run uv pip install pyvirtualdisplay pillow pytest-split
poetry run playwright install --with-deps poetry run playwright install --with-deps
- run: | - run: |
poetry run pytest tests/test_node_version.py poetry run pytest tests/test_node_version.py
poetry run pytest tests/integration poetry run pytest tests/integration --splits 2 --group ${{matrix.split_index}}

View File

@ -0,0 +1,88 @@
name: check-outdated-dependencies
on:
push: # This will trigger the action when a pull request is opened or updated.
branches:
- 'release/**' # This will trigger the action when any branch starting with "release/" is created.
workflow_dispatch: # Allow manual triggering if needed.
jobs:
backend:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- uses: ./.github/actions/setup_build_env
with:
python-version: '3.9'
run-poetry-install: true
create-venv-at-path: .venv
- name: Check outdated backend dependencies
run: |
outdated=$(poetry show -oT)
echo "Outdated:"
echo "$outdated"
filtered_outdated=$(echo "$outdated" | grep -vE 'pyright|ruff' || true)
if [ ! -z "$filtered_outdated" ]; then
echo "Outdated dependencies found:"
echo "$filtered_outdated"
exit 1
else
echo "All dependencies are up to date. (pyright and ruff are ignored)"
fi
frontend:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: '3.10.11'
run-poetry-install: true
create-venv-at-path: .venv
- name: Clone Reflex Website Repo
uses: actions/checkout@v4
with:
repository: reflex-dev/reflex-web
ref: main
path: reflex-web
- name: Install Requirements for reflex-web
working-directory: ./reflex-web
run: poetry run uv pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg
- name: Init Website for reflex-web
working-directory: ./reflex-web
run: poetry run reflex init
- name: Run Website and Check for errors
run: |
poetry run bash scripts/integration.sh ./reflex-web dev
- name: Check outdated frontend dependencies
working-directory: ./reflex-web/.web
run: |
raw_outdated=$(/home/runner/.local/share/reflex/bun/bin/bun outdated)
outdated=$(echo "$raw_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\|' || true)
echo "Outdated:"
echo "$outdated"
# 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)
no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true)
if [ ! -z "$no_extra" ]; then
echo "Outdated dependencies found:"
echo "$filtered_outdated"
exit 1
else
echo "All dependencies are up to date. (3rd party packages are ignored)"
fi

View File

@ -6,13 +6,13 @@ concurrency:
on: on:
push: push:
branches: ['main'] branches: ["main"]
paths-ignore: paths-ignore:
- '**/*.md' - "**/*.md"
pull_request: pull_request:
branches: ['main'] branches: ["main"]
paths-ignore: paths-ignore:
- '**/*.md' - "**/*.md"
permissions: permissions:
contents: read contents: read
@ -23,8 +23,10 @@ jobs:
strategy: strategy:
matrix: matrix:
state_manager: ['redis', 'memory'] state_manager: ['redis', 'memory']
python-version: ['3.11.5', '3.12.0'] python-version: ['3.11.5', '3.12.0', '3.13.0']
runs-on: ubuntu-latest split_index: [1, 2]
fail-fast: false
runs-on: ubuntu-22.04
services: services:
# Label used to access the service container # Label used to access the service container
redis: redis:
@ -45,13 +47,14 @@ 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 - run: poetry run uv pip install pyvirtualdisplay pillow pytest-split
- name: Run app harness tests - name: Run app harness tests
env: env:
SCREENSHOT_DIR: /tmp/screenshots 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 pytest tests/integration poetry run playwright install --with-deps
poetry run pytest tests/integration --splits 2 --group ${{matrix.split_index}}
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
name: Upload failed test screenshots name: Upload failed test screenshots
if: always() if: always()

View File

@ -42,8 +42,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
# Show OS combos first in GUI # Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-12] os: [ubuntu-latest, windows-latest]
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0'] python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0', '3.13.0']
exclude: exclude:
- os: windows-latest - os: windows-latest
python-version: '3.10.13' python-version: '3.10.13'
@ -73,7 +73,7 @@ jobs:
run: | run: |
poetry run uv pip install -r requirements.txt poetry run uv pip install -r requirements.txt
- name: Install additional dependencies for DB access - name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg2-binary run: poetry run uv pip install psycopg
- name: Check export --backend-only before init for counter example - name: Check export --backend-only before init for counter example
working-directory: ./reflex-examples/counter working-directory: ./reflex-examples/counter
run: | run: |
@ -122,7 +122,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
# Show OS combos first in GUI # Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-12] os: [ubuntu-latest]
python-version: ['3.10.11', '3.11.4'] python-version: ['3.10.11', '3.11.4']
env: env:
@ -145,9 +145,9 @@ jobs:
- 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 psycopg2-binary run: poetry run uv pip install psycopg
- name: Init Website for reflex-web - name: Init Website for reflex-web
working-directory: ./reflex-web working-directory: ./reflex-web
run: poetry run reflex init run: poetry run reflex init
@ -161,4 +161,74 @@ jobs:
poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}" poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}" --python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--pr-id "${{ github.event.pull_request.id }}" --branch-name "${{ github.head_ref || github.ref_name }}" --pr-id "${{ github.event.pull_request.id }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--app-name "reflex-web" --path ./reflex-web/.web --app-name "reflex-web" --path ./reflex-web/.web
rx-shout-from-template:
strategy:
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: '3.11.4'
run-poetry-install: true
create-venv-at-path: .venv
- name: Create app directory
run: mkdir rx-shout-from-template
- name: Init reflex-web from template
run: poetry run reflex init --template https://github.com/masenf/rx_shout
working-directory: ./rx-shout-from-template
- name: ignore reflex pin in requirements
run: sed -i -e '/reflex==/d' requirements.txt
working-directory: ./rx-shout-from-template
- name: Install additional dependencies
run: poetry run uv pip install -r requirements.txt
working-directory: ./rx-shout-from-template
- name: Run Website and Check for errors
run: |
# Check that npm is home
npm -v
poetry run bash scripts/integration.sh ./rx-shout-from-template prod
reflex-web-macos:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
fail-fast: false
matrix:
python-version: ['3.11.5', '3.12.0']
runs-on: macos-latest
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: Clone Reflex Website Repo
uses: actions/checkout@v4
with:
repository: reflex-dev/reflex-web
ref: main
path: reflex-web
- name: Install Requirements for reflex-web
working-directory: ./reflex-web
run: poetry run uv pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg
- name: Init Website for reflex-web
working-directory: ./reflex-web
run: poetry run reflex init
- name: Run Website and Check for errors
run: |
# Check that npm is home
npm -v
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

@ -27,8 +27,8 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-12] os: [ubuntu-latest, windows-latest]
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0'] python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0', '3.13.0']
# 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
@ -41,6 +41,7 @@ jobs:
- os: windows-latest - os: windows-latest
python-version: '3.9.13' 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`
services: services:
# Label used to access the service container # Label used to access the service container
@ -78,4 +79,31 @@ jobs:
export PYTHONUNBUFFERED=1 export PYTHONUNBUFFERED=1
poetry run uv pip install "pydantic~=1.10" poetry run uv pip install "pydantic~=1.10"
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report= poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
- run: poetry run coverage html - name: Generate coverage report
run: poetry run coverage html
unit-tests-macos:
timeout-minutes: 30
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
fail-fast: false
matrix:
# Note: py39, py310 versions chosen due to available arm64 darwin builds.
python-version: ['3.9.13', '3.10.11', '3.11.5', '3.12.0', '3.13.0']
runs-on: macos-latest
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 unit tests
run: |
export PYTHONUNBUFFERED=1
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
- name: Run unit tests w/ pydantic v1
run: |
export PYTHONUNBUFFERED=1
poetry run uv pip install "pydantic~=1.10"
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=

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.4.10 rev: v0.8.2
hooks: hooks:
- id: ruff-format - id: ruff-format
args: [reflex, tests] args: [reflex, tests]
@ -25,7 +25,7 @@ repos:
rev: v1.1.313 rev: v1.1.313
hooks: hooks:
- id: pyright - id: pyright
args: [integration, reflex, tests] args: [reflex, tests]
language: system language: system
- repo: https://github.com/terrencepreilly/darglint - repo: https://github.com/terrencepreilly/darglint

View File

@ -17,7 +17,7 @@
--- ---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) [English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) | [Tiếng Việt](https://github.com/reflex-dev/reflex/blob/main/docs/vi/README.md)
--- ---
@ -228,7 +228,7 @@ You can create a multi-page app by adding more pages.
<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>

View File

@ -3,8 +3,8 @@
from __future__ import annotations from __future__ import annotations
import json import json
import os
import sys import sys
from pathlib import Path
from utils import send_data_to_posthog from utils import send_data_to_posthog
@ -28,7 +28,7 @@ def insert_benchmarking_data(
send_data_to_posthog("lighthouse_benchmark", properties) send_data_to_posthog("lighthouse_benchmark", properties)
def get_lighthouse_scores(directory_path: str) -> dict: def get_lighthouse_scores(directory_path: str | Path) -> dict:
"""Extracts the Lighthouse scores from the JSON files in the specified directory. """Extracts the Lighthouse scores from the JSON files in the specified directory.
Args: Args:
@ -38,24 +38,20 @@ def get_lighthouse_scores(directory_path: str) -> dict:
dict: The Lighthouse scores. dict: The Lighthouse scores.
""" """
scores = {} scores = {}
directory_path = Path(directory_path)
try: try:
for filename in os.listdir(directory_path): for filename in directory_path.iterdir():
if filename.endswith(".json") and filename != "manifest.json": if filename.suffix == ".json" and filename.stem != "manifest":
file_path = os.path.join(directory_path, filename) data = json.loads(filename.read_text())
with open(file_path, "r") as file: # Extract scores and add them to the dictionary with the filename as key
data = json.load(file) scores[data["finalUrl"].replace("http://localhost:3000/", "/")] = {
# Extract scores and add them to the dictionary with the filename as key "performance_score": data["categories"]["performance"]["score"],
scores[data["finalUrl"].replace("http://localhost:3000/", "/")] = { "accessibility_score": data["categories"]["accessibility"]["score"],
"performance_score": data["categories"]["performance"]["score"], "best_practices_score": data["categories"]["best-practices"][
"accessibility_score": data["categories"]["accessibility"][ "score"
"score" ],
], "seo_score": data["categories"]["seo"]["score"],
"best_practices_score": data["categories"]["best-practices"][ }
"score"
],
"seo_score": data["categories"]["seo"]["score"],
}
except Exception as e: except Exception as e:
return {"error": e} return {"error": e}

View File

@ -2,11 +2,12 @@
import argparse import argparse
import os import os
from pathlib import Path
from utils import get_directory_size, get_python_version, send_data_to_posthog from utils import get_directory_size, get_python_version, send_data_to_posthog
def get_package_size(venv_path, os_name): def get_package_size(venv_path: Path, os_name):
"""Get the size of a specified package. """Get the size of a specified package.
Args: Args:
@ -26,14 +27,12 @@ def get_package_size(venv_path, os_name):
is_windows = "windows" in os_name is_windows = "windows" in os_name
full_path = ( package_dir: Path = (
["lib", f"python{python_version}", "site-packages"] venv_path / "lib" / f"python{python_version}" / "site-packages"
if not is_windows if not is_windows
else ["Lib", "site-packages"] else venv_path / "Lib" / "site-packages"
) )
if not package_dir.exists():
package_dir = os.path.join(venv_path, *full_path)
if not os.path.exists(package_dir):
raise ValueError( raise ValueError(
"Error: Virtual environment does not exist or is not activated." "Error: Virtual environment does not exist or is not activated."
) )
@ -63,9 +62,9 @@ def insert_benchmarking_data(
path: The path to the dir or file to check size. path: The path to the dir or file to check size.
""" """
if "./dist" in path: if "./dist" in path:
size = get_directory_size(path) size = get_directory_size(Path(path))
else: else:
size = get_package_size(path, os_type_version) size = get_package_size(Path(path), os_type_version)
# Prepare the event data # Prepare the event data
properties = { properties = {

View File

@ -2,6 +2,7 @@
import argparse import argparse
import os import os
from pathlib import Path
from utils import get_directory_size, send_data_to_posthog from utils import get_directory_size, send_data_to_posthog
@ -28,7 +29,7 @@ def insert_benchmarking_data(
pr_id: The id of the PR. pr_id: The id of the PR.
path: The path to the dir or file to check size. path: The path to the dir or file to check size.
""" """
size = get_directory_size(path) size = get_directory_size(Path(path))
# Prepare the event data # Prepare the event data
properties = { properties = {

View File

@ -210,9 +210,9 @@ def app_with_one_page(
Yields: Yields:
an AppHarness instance an AppHarness instance
""" """
root = tmp_path_factory.mktemp(f"app1") root = tmp_path_factory.mktemp("app1")
yield AppHarness.create(root=root, app_source=AppWithOnePage) # type: ignore yield AppHarness.create(root=root, app_source=AppWithOnePage)
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
@ -227,7 +227,7 @@ def app_with_ten_pages(
Yields: Yields:
an AppHarness instance an AppHarness instance
""" """
root = tmp_path_factory.mktemp(f"app10") root = tmp_path_factory.mktemp("app10")
yield AppHarness.create( yield AppHarness.create(
root=root, root=root,
app_source=functools.partial( app_source=functools.partial(
@ -249,7 +249,7 @@ def app_with_hundred_pages(
Yields: Yields:
an AppHarness instance an AppHarness instance
""" """
root = tmp_path_factory.mktemp(f"app100") root = tmp_path_factory.mktemp("app100")
yield AppHarness.create( yield AppHarness.create(
root=root, root=root,
@ -272,11 +272,11 @@ def app_with_thousand_pages(
Yields: Yields:
an AppHarness instance an AppHarness instance
""" """
root = tmp_path_factory.mktemp(f"app1000") root = tmp_path_factory.mktemp("app1000")
yield AppHarness.create( yield AppHarness.create(
root=root, root=root,
app_source=functools.partial( # type: ignore app_source=functools.partial(
AppWithThousandPages, AppWithThousandPages,
render_comp=render_multiple_pages, # type: ignore render_comp=render_multiple_pages, # type: ignore
), ),
@ -295,7 +295,7 @@ def app_with_ten_thousand_pages(
Yields: Yields:
running AppHarness instance running AppHarness instance
""" """
root = tmp_path_factory.mktemp(f"app10000") root = tmp_path_factory.mktemp("app10000")
yield AppHarness.create( yield AppHarness.create(
root=root, root=root,

View File

@ -2,12 +2,13 @@
import os import os
import subprocess import subprocess
from pathlib import Path
import httpx import httpx
from httpx import HTTPError from httpx import HTTPError
def get_python_version(venv_path, os_name): def get_python_version(venv_path: Path, os_name):
"""Get the python version of python in a virtual env. """Get the python version of python in a virtual env.
Args: Args:
@ -18,13 +19,13 @@ def get_python_version(venv_path, os_name):
The python version. The python version.
""" """
python_executable = ( python_executable = (
os.path.join(venv_path, "bin", "python") venv_path / "bin" / "python"
if "windows" not in os_name if "windows" not in os_name
else os.path.join(venv_path, "Scripts", "python.exe") else venv_path / "Scripts" / "python.exe"
) )
try: try:
output = subprocess.check_output( output = subprocess.check_output(
[python_executable, "--version"], stderr=subprocess.STDOUT [str(python_executable), "--version"], stderr=subprocess.STDOUT
) )
python_version = output.decode("utf-8").strip().split()[1] python_version = output.decode("utf-8").strip().split()[1]
return ".".join(python_version.split(".")[:-1]) return ".".join(python_version.split(".")[:-1])
@ -32,7 +33,7 @@ def get_python_version(venv_path, os_name):
return None return None
def get_directory_size(directory): def get_directory_size(directory: Path):
"""Get the size of a directory in bytes. """Get the size of a directory in bytes.
Args: Args:
@ -44,8 +45,8 @@ def get_directory_size(directory):
total_size = 0 total_size = 0
for dirpath, _, filenames in os.walk(directory): for dirpath, _, filenames in os.walk(directory):
for f in filenames: for f in filenames:
fp = os.path.join(dirpath, f) fp = Path(dirpath) / f
total_size += os.path.getsize(fp) total_size += fp.stat().st_size
return total_size return total_size

View File

@ -23,9 +23,9 @@
# for example, pass `docker build --platform=linux/amd64 ...` # for example, pass `docker build --platform=linux/amd64 ...`
# Stage 1: init # Stage 1: init
FROM python:3.11 as init FROM python:3.13 as init
ARG uv=/root/.cargo/bin/uv ARG uv=/root/.local/bin/uv
# Install `uv` for faster package boostrapping # Install `uv` for faster package boostrapping
ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh
@ -48,11 +48,11 @@ RUN $uv pip install -r requirements.txt
RUN reflex init RUN reflex init
# Stage 2: copy artifacts into slim image # Stage 2: copy artifacts into slim image
FROM python:3.11-slim FROM python:3.13-slim
WORKDIR /app WORKDIR /app
RUN adduser --disabled-password --home /app reflex RUN adduser --disabled-password --home /app reflex
COPY --chown=reflex --from=init /app /app COPY --chown=reflex --from=init /app /app
# Install libpq-dev for psycopg2 (skip if not using postgres). # Install libpq-dev for psycopg (skip if not using postgres).
RUN apt-get update -y && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/* RUN apt-get update -y && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/*
USER reflex USER reflex
ENV PATH="/app/.venv/bin:$PATH" PYTHONUNBUFFERED=1 ENV PATH="/app/.venv/bin:$PATH" PYTHONUNBUFFERED=1

View File

@ -2,9 +2,9 @@
# instance of a Reflex app. # instance of a Reflex app.
# Stage 1: init # Stage 1: init
FROM python:3.11 as init FROM python:3.13 as init
ARG uv=/root/.cargo/bin/uv ARG uv=/root/.local/bin/uv
# Install `uv` for faster package boostrapping # Install `uv` for faster package boostrapping
ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh
@ -35,11 +35,11 @@ RUN rm -rf .web && mkdir .web
RUN mv /tmp/_static .web/_static RUN mv /tmp/_static .web/_static
# Stage 2: copy artifacts into slim image # Stage 2: copy artifacts into slim image
FROM python:3.11-slim FROM python:3.13-slim
WORKDIR /app WORKDIR /app
RUN adduser --disabled-password --home /app reflex RUN adduser --disabled-password --home /app reflex
COPY --chown=reflex --from=init /app /app COPY --chown=reflex --from=init /app /app
# Install libpq-dev for psycopg2 (skip if not using postgres). # Install libpq-dev for psycopg (skip if not using postgres).
RUN apt-get update -y && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/* RUN apt-get update -y && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/*
USER reflex USER reflex
ENV PATH="/app/.venv/bin:$PATH" PYTHONUNBUFFERED=1 ENV PATH="/app/.venv/bin:$PATH" PYTHONUNBUFFERED=1

View File

@ -15,7 +15,7 @@ services:
app: app:
environment: environment:
DB_URL: postgresql+psycopg2://postgres:secret@db/postgres DB_URL: postgresql+psycopg://postgres:secret@db/postgres
REDIS_URL: redis://redis:6379 REDIS_URL: redis://redis:6379
depends_on: depends_on:
- db - db

View File

@ -0,0 +1,3 @@
.web
!.web/bun.lockb
!.web/package.json

View File

@ -0,0 +1,14 @@
:{$PORT}
encode gzip
@backend_routes path /_event/* /ping /_upload /_upload/*
handle @backend_routes {
reverse_proxy localhost:8000
}
root * /srv
route {
try_files {path} {path}/ /404.html
file_server
}

View File

@ -0,0 +1,62 @@
# This Dockerfile is used to deploy a single-container Reflex app instance
# to services like Render, Railway, Heroku, GCP, and others.
# If the service expects a different port, provide it here (f.e Render expects port 10000)
ARG PORT=8080
# Only set for local/direct access. When TLS is used, the API_URL is assumed to be the same as the frontend.
ARG API_URL
# It uses a reverse proxy to serve the frontend statically and proxy to backend
# from a single exposed port, expecting TLS termination to be handled at the
# edge by the given platform.
FROM python:3.13 as builder
RUN mkdir -p /app/.web
RUN python -m venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
WORKDIR /app
# Install python app requirements and reflex in the container
COPY requirements.txt .
RUN pip install -r requirements.txt
# Install reflex helper utilities like bun/fnm/node
COPY rxconfig.py ./
RUN reflex init
# Install pre-cached frontend dependencies (if exist)
COPY *.web/bun.lockb *.web/package.json .web/
RUN if [ -f .web/bun.lockb ]; then cd .web && ~/.local/share/reflex/bun/bin/bun install --frozen-lockfile; fi
# Copy local context to `/app` inside container (see .dockerignore)
COPY . .
ARG PORT API_URL
# Download other npm dependencies and compile frontend
RUN API_URL=${API_URL:-http://localhost:$PORT} reflex export --loglevel debug --frontend-only --no-zip && mv .web/_static/* /srv/ && rm -rf .web
# Final image with only necessary files
FROM python:3.13-slim
# Install Caddy and redis server inside image
RUN apt-get update -y && apt-get install -y caddy redis-server && rm -rf /var/lib/apt/lists/*
ARG PORT API_URL
ENV PATH="/app/.venv/bin:$PATH" PORT=$PORT API_URL=${API_URL:-http://localhost:$PORT} REDIS_URL=redis://localhost PYTHONUNBUFFERED=1
WORKDIR /app
COPY --from=builder /app /app
COPY --from=builder /srv /srv
# Needed until Reflex properly passes SIGTERM on backend.
STOPSIGNAL SIGKILL
EXPOSE $PORT
# Apply migrations before starting the backend.
CMD [ -d alembic ] && reflex db migrate; \
caddy start && \
redis-server --daemonize yes && \
exec reflex run --env prod --backend-only

View File

@ -0,0 +1,37 @@
# production-one-port
This docker deployment runs Reflex in prod mode, exposing a single HTTP port:
* `8080` (`$PORT`) - Caddy server hosting the frontend statically and proxying requests to the backend.
The deployment also runs a local Redis server to store state for each user.
Conceptually it is similar to the `simple-one-port` example except it:
* has layer caching for python, reflex, and node dependencies
* uses multi-stage build to reduce the size of the final image
Using this method may be preferable for deploying in memory constrained
environments, because it serves a static frontend export, rather than running
the NextJS server via node.
## Build
```console
docker build -t reflex-production-one-port .
```
## Run
```console
docker run -p 8080:8080 reflex-production-one-port
```
Note that this container has _no persistence_ and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.
## Usage
This container should be used with an existing load balancer or reverse proxy to
terminate TLS.
It is also useful for deploying to simple app platforms, such as Render or Heroku.

View File

@ -11,4 +11,4 @@ root * /srv
route { route {
try_files {path} {path}/ /404.html try_files {path} {path}/ /404.html
file_server file_server
} }

View File

@ -4,7 +4,7 @@
# It uses a reverse proxy to serve the frontend statically and proxy to backend # It uses a reverse proxy to serve the frontend statically and proxy to backend
# from a single exposed port, expecting TLS termination to be handled at the # from a single exposed port, expecting TLS termination to be handled at the
# edge by the given platform. # edge by the given platform.
FROM python:3.11 FROM python:3.13
# If the service expects a different port, provide it here (f.e Render expects port 10000) # If the service expects a different port, provide it here (f.e Render expects port 10000)
ARG PORT=8080 ARG PORT=8080
@ -38,4 +38,4 @@ EXPOSE $PORT
CMD [ -d alembic ] && reflex db migrate; \ CMD [ -d alembic ] && reflex db migrate; \
caddy start && \ caddy start && \
redis-server --daemonize yes && \ redis-server --daemonize yes && \
exec reflex run --env prod --backend-only exec reflex run --env prod --backend-only

View File

@ -1,5 +1,5 @@
# This Dockerfile is used to deploy a simple single-container Reflex app instance. # This Dockerfile is used to deploy a simple single-container Reflex app instance.
FROM python:3.12 FROM python:3.13
RUN apt-get update && apt-get install -y redis-server && rm -rf /var/lib/apt/lists/* RUN apt-get update && apt-get install -y redis-server && rm -rf /var/lib/apt/lists/*
ENV REDIS_URL=redis://localhost PYTHONUNBUFFERED=1 ENV REDIS_URL=redis://localhost PYTHONUNBUFFERED=1

267
docs/vi/README.md Normal file
View File

@ -0,0 +1,267 @@
```diff
+ Bạn đang tìm kiếm Pynecone? Bạn đã tìm đúng. Pynecone đã được đổi tên thành Reflex. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ Ứng dụng web hiệu suất cao, tùy chỉnh bằng Python thuần. Deploy trong vài giây. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) | [Tiếng Việt](https://github.com/reflex-dev/reflex/blob/main/docs/vi/README.md)
---
# Reflex
Reflex là một thư viện để xây dựng ứng dụng web toàn bộ bằng Python thuần.
Các tính năng chính:
* **Python thuần tuý** - Viết toàn bộ ứng dụng cả backend và frontend hoàn toàn bằng Python, không cần học JavaScript.
* **Full Flexibility** - Reflex dễ dàng để bắt đầu, nhưng cũng có thể mở rộng lên các ứng dụng phức tạp.
* **Deploy Instantly** - Sau khi xây dựng ứng dụng, bạn có thể triển khai bằng [một dòng lệnh](https://reflex.dev/docs/hosting/deploy-quick-start/) hoặc triển khai trên server của riêng bạn.
Đọc [bài viết về kiến trúc hệ thống](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) để hiểu rõ các hoạt động của Reflex.
## ⚙️ Cài đặt
Mở cửa sổ lệnh và chạy (Yêu cầu Python phiên bản 3.9+):
```bash
pip install reflex
```
## 🥳 Tạo ứng dụng đầu tiên
Cài đặt `reflex` cũng như cài đặt công cụ dòng lệnh `reflex`.
Kiểm tra việc cài đặt đã thành công hay chưa bằng cách tạo mới một ứng dụng. (Thay `my_app_name` bằng tên ứng dụng của bạn):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
Lệnh này tạo ra một ứng dụng mẫu trong một thư mục mới.
Bạn có thể chạy ứng dụng ở chế độ phát triển.
```bash
reflex run
```
Bạn có thể xem ứng dụng của bạn ở địa chỉ http://localhost:3000.
Bạn có thể thay đổi mã nguồn ở `my_app_name/my_app_name.py`. Reflex nhanh chóng làm mới và bạn có thể thấy thay đổi trên ứng dụng của bạn ngay lập tức khi bạn lưu file.
## 🫧 Ứng dụng ví dụ
Bắt đầu với ví dụ: tạo một ứng dụng tạo ảnh bằng [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). Để cho đơn giản, chúng ta sẽ sử dụng [OpenAI API](https://platform.openai.com/docs/api-reference/authentication), nhưng bạn có thể sử dụng model của chính bạn được triển khai trên local.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
</div>
&nbsp;
Đây là toàn bộ đoạn mã để xây dựng ứng dụng trên. Nó được viết hoàn toàn trong một file Python!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## Hãy phân tích chi tiết.
<div align="center">
<img src="../images/dalle_colored_code_example.png" alt="Explaining the differences between backend and frontend parts of the DALL-E app." width="900" />
</div>
### **Reflex UI**
Bắt đầu với giao diện chính.
```python
def index():
return rx.center(
...
)
```
Hàm `index` định nghĩa phần giao diện chính của ứng dụng.
Chúng tôi sử dụng các component (thành phần) khác nhau như `center`, `vstack`, `input``button` để xây dựng giao diện phía trước.
Các component có thể được lồng vào nhau để tạo ra các bố cục phức tạp. Và bạn cũng có thể sử dụng từ khoá `args` để tận dụng đầy đủ sức mạnh của CSS.
Reflex có đến hơn [60 component được xây dựng sẵn](https://reflex.dev/docs/library) để giúp bạn bắt đầu. Chúng ta có thể tạo ra một component mới khá dễ dàng, thao khảo: [xây dựng component của riêng bạn](https://reflex.dev/docs/wrapping-react/overview/).
### **State**
Reflex biểu diễn giao diện bằng các hàm của state (trạng thái).
```python
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
```
Một state định nghĩa các biến (được gọi là vars) có thể thay đổi trong một ứng dụng và cho phép các hàm có thể thay đổi chúng.
Tại đây state được cấu thành từ một `prompt``image_url`.
Có cũng những biến boolean `processing``complete`
để chỉ ra khi nào tắt nút (trong quá trình tạo hình ảnh)
và khi nào hiển thị hình ảnh kết quả.
### **Event Handlers**
```python
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
Với các state, chúng ta định nghĩa các hàm có thể thay đổi state vars được gọi là event handlers. Event handler là cách chúng ta có thể thay đổi state trong Reflex. Chúng có thể là phản hồi khi người dùng thao tác, chằng hạn khi nhấn vào nút hoặc khi đang nhập trong text box. Các hành động này được gọi là event.
Ứng dụng DALL·E. của chúng ta có một event handler, `get_image` để lấy hình ảnh từ OpenAI API. Sử dụng từ khoá `yield` in ở giữa event handler để cập nhật giao diện. Hoặc giao diện có thể cập nhật ở cuối event handler.
### **Routing**
Cuối cùng, chúng ta định nghĩa một ứng dụng.
```python
app = rx.App()
```
Chúng ta thêm một trang ở đầu ứng dụng bằng index component. Chúng ta cũng thêm tiêu đề của ứng dụng để hiển thị lên trình duyệt.
```python
app.add_page(index, title="DALL-E")
```
Bạn có thể tạo một ứng dụng nhiều trang bằng cách thêm trang.
## 📑 Tài liệu
<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;
</div>
## ✅ Status
Reflex phát hành vào tháng 12/2022 với tên là Pynecone.
Đến tháng 02/2024, chúng tôi tạo ra dịch vụ dưới phiên bản alpha! Trong thời gian này mọi người có thể triển khai ứng dụng hoàn toàn miễn phí. Xem [roadmap](https://github.com/reflex-dev/reflex/issues/2727) để biết thêm chi tiết.
Reflex ra phiên bản mới với các tính năng mới hàng tuần! Hãy :star: star và :eyes: watch repo này để thấy các cập nhật mới nhất.
## Contributing
Chúng tôi chào đón mọi đóng góp dù lớn hay nhỏ. Dưới đây là các cách để bắt đầu với cộng đồng Reflex.
- **Discord**: [Discord](https://discord.gg/T5WSbC2YtQ) của chúng tôi là nơi tốt nhất để nhờ sự giúp đỡ và thảo luận các bạn có thể đóng góp.
- **GitHub Discussions**: Là cách tốt nhất để thảo luận về các tính năng mà bạn có thể đóng góp hoặc những điều bạn chưa rõ.
- **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
[CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## Xin cảm ơn các Contributors:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## License
Reflex là mã nguồn mở và sử dụng giấy phép [Apache License 2.0](LICENSE).

2053
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.1dev1" version = "0.6.7dev1"
description = "Web apps in pure Python." description = "Web apps in pure Python."
license = "Apache-2.0" license = "Apache-2.0"
authors = [ authors = [
@ -27,7 +27,6 @@ packages = [
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.9" python = "^3.9"
dill = ">=0.3.8,<0.4"
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"
@ -50,33 +49,35 @@ wrapt = [
{version = ">=1.11.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.2,<2.0" reflex-hosting-cli = ">=0.1.29,<2.0"
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"
setuptools = ">=69.1.1,<70.2" setuptools = ">=75.0"
httpx = ">=0.25.1,<1.0" httpx = ">=0.25.1,<1.0"
twine = ">=4.0.0,<6.0" twine = ">=4.0.0,<7.0"
tomlkit = ">=0.12.4,<1.0" tomlkit = ">=0.12.4,<1.0"
lazy_loader = ">=0.4" lazy_loader = ">=0.4"
reflex-chakra = ">=0.6.0" reflex-chakra = ">=0.6.0"
typing_extensions = ">=4.6.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest = ">=7.1.2,<8.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.229,<1.1.335"
darglint = ">=1.8.1,<2.0" darglint = ">=1.8.1,<2.0"
dill = ">=0.3.8"
toml = ">=0.10.2,<1.0" toml = ">=0.10.2,<1.0"
pytest-asyncio = ">=0.20.1,<0.22.0" # https://github.com/pytest-dev/pytest-asyncio/issues/706 pytest-asyncio = ">=0.24.0"
pytest-cov = ">=4.0.0,<5.0" pytest-cov = ">=4.0.0,<7.0"
ruff = "^0.4.9" ruff = "0.8.2"
pandas = ">=2.1.1,<3.0" pandas = ">=2.1.1,<3.0"
pillow = ">=10.0.0,<11.0" pillow = ">=10.0.0,<12.0"
plotly = ">=5.13.0,<6.0" plotly = ">=5.13.0,<6.0"
asynctest = ">=0.13.0,<1.0" asynctest = ">=0.13.0,<1.0"
pre-commit = ">=3.2.1" pre-commit = ">=3.2.1"
selenium = ">=4.11.0,<5.0" selenium = ">=4.11.0,<5.0"
pytest-benchmark = ">=4.0.0,<5.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"
@ -91,8 +92,9 @@ build-backend = "poetry.core.masonry.api"
[tool.ruff] [tool.ruff]
target-version = "py39" target-version = "py39"
lint.select = ["B", "D", "E", "F", "I", "SIM", "W"] lint.isort.split-on-trailing-comma = false
lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541"] lint.select = ["B", "D", "E", "F", "I", "SIM", "W", "RUF", "FURB", "ERA"]
lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012"]
lint.pydocstyle.convention = "google" lint.pydocstyle.convention = "google"
[tool.ruff.lint.per-file-ignores] [tool.ruff.lint.per-file-ignores]
@ -101,3 +103,7 @@ lint.pydocstyle.convention = "google"
"reflex/.templates/*.py" = ["D100", "D103", "D104"] "reflex/.templates/*.py" = ["D100", "D103", "D104"]
"*.pyi" = ["D301", "D415", "D417", "D418", "E742"] "*.pyi" = ["D301", "D415", "D417", "D418", "E742"]
"*/blank.py" = ["I001"] "*/blank.py" = ["I001"]
[tool.pytest.ini_options]
asyncio_default_fixture_loop_scope = "function"
asyncio_mode = "auto"

View File

@ -1,16 +1,15 @@
{% extends "web/pages/base_page.js.jinja2" %} {% extends "web/pages/base_page.js.jinja2" %}
{% block early_imports %} {% block early_imports %}
import '/styles/styles.css' import '$/styles/styles.css'
{% endblock %} {% endblock %}
{% block declaration %} {% block declaration %}
import { EventLoopProvider, StateProvider, defaultColorMode } from "/utils/context.js"; import { EventLoopProvider, StateProvider, defaultColorMode } from "$/utils/context.js";
import { ThemeProvider } from 'next-themes' import { ThemeProvider } from 'next-themes'
import * as React from "react"; {% for library_alias, library_path in window_libraries %}
import * as utils_context from "/utils/context.js"; import * as {{library_alias}} from "{{library_path}}";
import * as utils_state from "/utils/state.js"; {% endfor %}
import * as radix from "@radix-ui/themes";
{% for custom_code in custom_codes %} {% for custom_code in custom_codes %}
{{custom_code}} {{custom_code}}
@ -33,10 +32,9 @@ export default function MyApp({ Component, pageProps }) {
React.useEffect(() => { React.useEffect(() => {
// Make contexts and state objects available globally for dynamic eval'd components // Make contexts and state objects available globally for dynamic eval'd components
let windowImports = { let windowImports = {
"react": React, {% for library_alias, library_path in window_libraries %}
"@radix-ui/themes": radix, "{{library_path}}": {{library_alias}},
"/utils/context": utils_context, {% endfor %}
"/utils/state": utils_state,
}; };
window["__reflex"] = windowImports; window["__reflex"] = windowImports;
}, []); }, []);

View File

@ -8,20 +8,6 @@
{% endfor %} {% endfor %}
export const {{component.name}} = memo(({ {{-component.props|join(", ")-}} }) => { export const {{component.name}} = memo(({ {{-component.props|join(", ")-}} }) => {
{% if component.name == "CodeBlock" and "language" in component.props %}
if (language) {
(async () => {
try {
const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${language}`);
SyntaxHighlighter.registerLanguage(language, module.default);
} catch (error) {
console.error(`Error importing language module for ${language}:`, error);
}
})();
}
{% endif %}
{% for hook in component.hooks %} {% for hook in component.hooks %}
{{ hook }} {{ hook }}
{% endfor %} {% endfor %}

View File

@ -36,14 +36,10 @@
{# component: component dictionary #} {# component: component dictionary #}
{% macro render_tag(component) %} {% macro render_tag(component) %}
<{{component.name}} {{- render_props(component.props) }}> <{{component.name}} {{- render_props(component.props) }}>
{%- if component.args is not none -%} {{ component.contents }}
{{- render_arg_content(component) }} {% for child in component.children %}
{%- else -%} {{ render(child) }}
{{ component.contents }} {% endfor %}
{% for child in component.children %}
{{ render(child) }}
{% endfor %}
{%- endif -%}
</{{component.name}}> </{{component.name}}>
{%- endmacro %} {%- endmacro %}

View File

@ -1,5 +1,5 @@
import { createContext, useContext, useMemo, useReducer, useState } from "react" import { createContext, useContext, useMemo, useReducer, useState } from "react"
import { applyDelta, Event, hydrateClientStorage, useEventLoop, refs } from "/utils/state.js" import { applyDelta, Event, hydrateClientStorage, useEventLoop, refs } from "$/utils/state.js"
{% if initial_state %} {% if initial_state %}
export const initialState = {{ initial_state|json_dumps }} export const initialState = {{ initial_state|json_dumps }}
@ -59,6 +59,8 @@ export const initialEvents = () => [
{% else %} {% else %}
export const state_name = undefined export const state_name = undefined
export const exception_state_name = undefined
export const onLoadInternalEvent = () => [] export const onLoadInternalEvent = () => []
export const initialEvents = () => [] export const initialEvents = () => []

View File

@ -4,8 +4,8 @@ import {
ColorModeContext, ColorModeContext,
defaultColorMode, defaultColorMode,
isDevMode, isDevMode,
lastCompiledTimeStamp lastCompiledTimeStamp,
} from "/utils/context.js"; } from "$/utils/context.js";
export default function RadixThemesColorModeProvider({ children }) { export default function RadixThemesColorModeProvider({ children }) {
const { theme, resolvedTheme, setTheme } = useTheme(); const { theme, resolvedTheme, setTheme } = useTheme();
@ -37,7 +37,7 @@ export default function RadixThemesColorModeProvider({ children }) {
const allowedModes = ["light", "dark", "system"]; const allowedModes = ["light", "dark", "system"];
if (!allowedModes.includes(mode)) { if (!allowedModes.includes(mode)) {
console.error( console.error(
`Invalid color mode "${mode}". Defaulting to "${defaultColorMode}".`, `Invalid color mode "${mode}". Defaulting to "${defaultColorMode}".`
); );
mode = defaultColorMode; mode = defaultColorMode;
} }

View File

@ -0,0 +1,34 @@
import { useEffect, useState } from "react"
import { codeToHtml} from "shiki"
/**
* Code component that uses Shiki to convert code to HTML and render it.
*
* @param code - The code to be highlighted.
* @param theme - The theme to be used for highlighting.
* @param language - The language of the code.
* @param transformers - The transformers to be applied to the code.
* @param decorations - The decorations to be applied to the code.
* @param divProps - Additional properties to be passed to the div element.
* @returns The rendered code block.
*/
export function Code ({code, theme, language, transformers, decorations, ...divProps}) {
const [codeResult, setCodeResult] = useState("")
useEffect(() => {
async function fetchCode() {
const result = await codeToHtml(code, {
lang: language,
theme,
transformers,
decorations
});
setCodeResult(result);
}
fetchCode();
}, [code, language, theme, transformers, decorations]
)
return (
<div dangerouslySetInnerHTML={{__html: codeResult}} {...divProps} ></div>
)
}

View File

@ -2,7 +2,8 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"$/*": ["*"],
"@/*": ["public/*"] "@/*": ["public/*"]
} }
} }
} }

View File

@ -2,7 +2,7 @@
import axios from "axios"; 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 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";
@ -12,10 +12,9 @@ import {
onLoadInternalEvent, onLoadInternalEvent,
state_name, state_name,
exception_state_name, exception_state_name,
} from "utils/context.js"; } from "$/utils/context.js";
import debounce from "/utils/helpers/debounce"; import debounce from "$/utils/helpers/debounce";
import throttle from "/utils/helpers/throttle"; import throttle from "$/utils/helpers/throttle";
import * as Babel from "@babel/standalone";
// Endpoint URLs. // Endpoint URLs.
const EVENTURL = env.EVENT; const EVENTURL = env.EVENT;
@ -41,9 +40,6 @@ let event_processing = false;
// Array holding pending events to be processed. // Array holding pending events to be processed.
const event_queue = []; const event_queue = [];
// Pending upload promises, by id
const upload_controllers = {};
/** /**
* Generate a UUID (Used for session tokens). * Generate a UUID (Used for session tokens).
* Taken from: https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid * Taken from: https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid
@ -139,8 +135,7 @@ export const evalReactComponent = async (component) => {
if (!window.React && window.__reflex) { if (!window.React && window.__reflex) {
window.React = window.__reflex.react; window.React = window.__reflex.react;
} }
const output = Babel.transform(component, { presets: ["react"] }).code; const encodedJs = encodeURIComponent(component);
const encodedJs = encodeURIComponent(output);
const dataUri = "data:text/javascript;charset=utf-8," + encodedJs; const dataUri = "data:text/javascript;charset=utf-8," + encodedJs;
const module = await eval(`import(dataUri)`); const module = await eval(`import(dataUri)`);
return module.default; return module.default;
@ -180,11 +175,6 @@ export const applyEvent = async (event, socket) => {
return false; return false;
} }
if (event.name == "_console") {
console.log(event.payload.message);
return false;
}
if (event.name == "_remove_cookie") { if (event.name == "_remove_cookie") {
cookies.remove(event.payload.key, { ...event.payload.options }); cookies.remove(event.payload.key, { ...event.payload.options });
queueEventIfSocketExists(initialEvents(), socket); queueEventIfSocketExists(initialEvents(), socket);
@ -215,12 +205,6 @@ export const applyEvent = async (event, socket) => {
return false; return false;
} }
if (event.name == "_set_clipboard") {
const content = event.payload.content;
navigator.clipboard.writeText(content);
return false;
}
if (event.name == "_download") { if (event.name == "_download") {
const a = document.createElement("a"); const a = document.createElement("a");
a.hidden = true; a.hidden = true;
@ -235,11 +219,6 @@ export const applyEvent = async (event, socket) => {
return false; return false;
} }
if (event.name == "_alert") {
alert(event.payload.message);
return false;
}
if (event.name == "_set_focus") { if (event.name == "_set_focus") {
const ref = const ref =
event.payload.ref in refs ? refs[event.payload.ref] : event.payload.ref; event.payload.ref in refs ? refs[event.payload.ref] : event.payload.ref;
@ -256,9 +235,35 @@ export const applyEvent = async (event, socket) => {
return false; return false;
} }
if (event.name == "_call_script") { if (
event.name == "_call_function" &&
typeof event.payload.function !== "string"
) {
try { try {
const eval_result = eval(event.payload.javascript_code); const eval_result = event.payload.function();
if (event.payload.callback) {
if (!!eval_result && typeof eval_result.then === "function") {
event.payload.callback(await eval_result);
} else {
event.payload.callback(eval_result);
}
}
} catch (e) {
console.log("_call_function", e);
if (window && window?.onerror) {
window.onerror(e.message, null, null, null, e);
}
}
return false;
}
if (event.name == "_call_script" || event.name == "_call_function") {
try {
const eval_result =
event.name == "_call_script"
? eval(event.payload.javascript_code)
: eval(event.payload.function)();
if (event.payload.callback) { if (event.payload.callback) {
if (!!eval_result && typeof eval_result.then === "function") { if (!!eval_result && typeof eval_result.then === "function") {
eval(event.payload.callback)(await eval_result); eval(event.payload.callback)(await eval_result);
@ -292,7 +297,7 @@ export const applyEvent = async (event, socket) => {
if (socket) { if (socket) {
socket.emit( socket.emit(
"event", "event",
JSON.stringify(event, (k, v) => (v === undefined ? null : v)) event,
); );
return true; return true;
} }
@ -399,6 +404,8 @@ export const connect = async (
transports: transports, transports: transports,
autoUnref: false, autoUnref: false,
}); });
// Ensure undefined fields in events are sent as null instead of removed
socket.current.io.encoder.replacer = (k, v) => (v === undefined ? null : v)
function checkVisibility() { function checkVisibility() {
if (document.visibilityState === "visible") { if (document.visibilityState === "visible") {
@ -435,8 +442,7 @@ export const connect = async (
}); });
// On each received message, queue the updates and events. // On each received message, queue the updates and events.
socket.current.on("event", async (message) => { socket.current.on("event", async (update) => {
const update = JSON5.parse(message);
for (const substate in update.delta) { for (const substate in update.delta) {
dispatch[substate](update.delta[substate]); dispatch[substate](update.delta[substate]);
} }
@ -446,6 +452,10 @@ export const connect = async (
queueEvents(update.events, socket); queueEvents(update.events, socket);
} }
}); });
socket.current.on("reload", async (event) => {
event_processing = false;
queueEvents([...initialEvents(), event], socket);
});
document.addEventListener("visibilitychange", checkVisibility); document.addEventListener("visibilitychange", checkVisibility);
}; };
@ -473,25 +483,42 @@ export const uploadFiles = async (
return false; return false;
} }
if (upload_controllers[upload_id]) { const upload_ref_name = `__upload_controllers_${upload_id}`
if (refs[upload_ref_name]) {
console.log("Upload already in progress for ", upload_id); console.log("Upload already in progress for ", upload_id);
return false; return false;
} }
// Track how many partial updates have been processed for this upload.
let resp_idx = 0; let resp_idx = 0;
const eventHandler = (progressEvent) => { const eventHandler = (progressEvent) => {
// handle any delta / event streamed from the upload event handler const event_callbacks = socket._callbacks.$event;
// Whenever called, responseText will contain the entire response so far.
const chunks = progressEvent.event.target.responseText.trim().split("\n"); const chunks = progressEvent.event.target.responseText.trim().split("\n");
chunks.slice(resp_idx).map((chunk) => { // So only process _new_ chunks beyond resp_idx.
chunks.slice(resp_idx).map((chunk_json) => {
try { try {
socket._callbacks.$event.map((f) => { const chunk = JSON5.parse(chunk_json);
f(chunk); event_callbacks.map((f, ix) => {
f(chunk)
.then(() => {
if (ix === event_callbacks.length - 1) {
// Mark this chunk as processed.
resp_idx += 1;
}
})
.catch((e) => {
if (progressEvent.progress === 1) {
// Chunk may be incomplete, so only report errors when full response is available.
console.log("Error processing chunk", chunk, e);
}
return;
});
}); });
resp_idx += 1;
} catch (e) { } catch (e) {
if (progressEvent.progress === 1) { if (progressEvent.progress === 1) {
// Chunk may be incomplete, so only report errors when full response is available. console.log("Error parsing chunk", chunk_json, e);
console.log("Error parsing chunk", chunk, e);
} }
return; return;
} }
@ -518,7 +545,7 @@ export const uploadFiles = async (
}); });
// Send the file to the server. // Send the file to the server.
upload_controllers[upload_id] = controller; refs[upload_ref_name] = controller;
try { try {
return await axios.post(getBackendURL(UPLOADURL), formdata, config); return await axios.post(getBackendURL(UPLOADURL), formdata, config);
@ -538,19 +565,25 @@ export const uploadFiles = async (
} }
return false; return false;
} finally { } finally {
delete upload_controllers[upload_id]; delete refs[upload_ref_name];
} }
}; };
/** /**
* Create an event object. * Create an event object.
* @param name The name of the event. * @param {string} name The name of the event.
* @param payload The payload of the event. * @param {Object.<string, Any>} payload The payload of the event.
* @param handler The client handler to process event. * @param {Object.<string, (number|boolean)>} event_actions The actions to take on the event.
* @param {string} handler The client handler to process event.
* @returns The event object. * @returns The event object.
*/ */
export const Event = (name, payload = {}, handler = null) => { export const Event = (
return { name, payload, handler }; name,
payload = {},
event_actions = {},
handler = null
) => {
return { name, payload, handler, event_actions };
}; };
/** /**
@ -676,6 +709,12 @@ export const useEventLoop = (
if (!(args instanceof Array)) { if (!(args instanceof Array)) {
args = [args]; args = [args];
} }
event_actions = events.reduce(
(acc, e) => ({ ...acc, ...e.event_actions }),
event_actions ?? {}
);
const _e = args.filter((o) => o?.preventDefault !== undefined)[0]; const _e = args.filter((o) => o?.preventDefault !== undefined)[0];
if (event_actions?.preventDefault && _e?.preventDefault) { if (event_actions?.preventDefault && _e?.preventDefault) {
@ -685,6 +724,11 @@ export const useEventLoop = (
_e.stopPropagation(); _e.stopPropagation();
} }
const combined_name = events.map((e) => e.name).join("+++"); const combined_name = events.map((e) => e.name).join("+++");
if (event_actions?.temporal) {
if (!socket.current || !socket.current.connected) {
return; // don't queue when the backend is not connected
}
}
if (event_actions?.throttle) { if (event_actions?.throttle) {
// If throttle returns false, the events are not added to the queue. // If throttle returns false, the events are not added to the queue.
if (!throttle(combined_name, event_actions.throttle)) { if (!throttle(combined_name, event_actions.throttle)) {
@ -731,6 +775,7 @@ export const useEventLoop = (
addEvents([ addEvents([
Event(`${exception_state_name}.handle_frontend_exception`, { Event(`${exception_state_name}.handle_frontend_exception`, {
stack: error.stack, stack: error.stack,
component_stack: "",
}), }),
]); ]);
return false; return false;
@ -741,7 +786,8 @@ export const useEventLoop = (
window.onunhandledrejection = function (event) { window.onunhandledrejection = function (event) {
addEvents([ addEvents([
Event(`${exception_state_name}.handle_frontend_exception`, { Event(`${exception_state_name}.handle_frontend_exception`, {
stack: event.reason.stack, stack: event.reason?.stack,
component_stack: "",
}), }),
]); ]);
return false; return false;
@ -761,7 +807,7 @@ export const useEventLoop = (
connect( connect(
socket, socket,
dispatch, dispatch,
["websocket", "polling"], ["websocket"],
setConnectErrors, setConnectErrors,
client_storage client_storage
); );
@ -815,11 +861,20 @@ export const useEventLoop = (
} }
}; };
const change_complete = () => addEvents(onLoadInternalEvent()); const change_complete = () => addEvents(onLoadInternalEvent());
const change_error = () => {
// Remove cached error state from router for this page, otherwise the
// page will never send on_load events again.
if (router.components[router.pathname].error) {
delete router.components[router.pathname].error;
}
};
router.events.on("routeChangeStart", change_start); router.events.on("routeChangeStart", change_start);
router.events.on("routeChangeComplete", change_complete); router.events.on("routeChangeComplete", change_complete);
router.events.on("routeChangeError", change_error);
return () => { return () => {
router.events.off("routeChangeStart", change_start); router.events.off("routeChangeStart", change_start);
router.events.off("routeChangeComplete", change_complete); router.events.off("routeChangeComplete", change_complete);
router.events.off("routeChangeError", change_error);
}; };
}, [router]); }, [router]);

View File

@ -89,6 +89,8 @@ from reflex.utils import (
lazy_loader, lazy_loader,
) )
from .event import event as event
# import this here explicitly to avoid returning the page module since page attr has the # import this here explicitly to avoid returning the page module since page attr has the
# same name as page module(page.py) # same name as page module(page.py)
from .page import page as page from .page import page as page
@ -262,6 +264,7 @@ _MAPPING: dict = {
"experimental": ["_x"], "experimental": ["_x"],
"admin": ["AdminDash"], "admin": ["AdminDash"],
"app": ["App", "UploadFile"], "app": ["App", "UploadFile"],
"assets": ["asset"],
"base": ["Base"], "base": ["Base"],
"components.component": [ "components.component": [
"Component", "Component",
@ -296,15 +299,19 @@ _MAPPING: dict = {
"components.moment": ["MomentDelta", "moment"], "components.moment": ["MomentDelta", "moment"],
"config": ["Config", "DBConfig"], "config": ["Config", "DBConfig"],
"constants": ["Env"], "constants": ["Env"],
"constants.colors": ["Color"],
"event": [ "event": [
"EventChain", "EventChain",
"EventHandler", "EventHandler",
"background", "background",
"call_script", "call_script",
"call_function",
"run_script",
"clear_local_storage", "clear_local_storage",
"clear_session_storage", "clear_session_storage",
"console_log", "console_log",
"download", "download",
"noop",
"prevent_default", "prevent_default",
"redirect", "redirect",
"remove_cookie", "remove_cookie",
@ -318,25 +325,28 @@ _MAPPING: dict = {
"upload_files", "upload_files",
"window_alert", "window_alert",
], ],
"middleware": ["middleware", "Middleware"], "istate.storage": [
"model": ["session", "Model"],
"state": [
"var",
"Cookie", "Cookie",
"LocalStorage", "LocalStorage",
"SessionStorage", "SessionStorage",
],
"middleware": ["middleware", "Middleware"],
"model": ["asession", "session", "Model"],
"state": [
"var",
"ComponentState", "ComponentState",
"State", "State",
"dynamic",
], ],
"istate.wrappers": ["get_state"],
"style": ["Style", "toggle_color_mode"], "style": ["Style", "toggle_color_mode"],
"utils.imports": ["ImportVar"], "utils.imports": ["ImportDict", "ImportVar"],
"utils.serializers": ["serializer"], "utils.serializers": ["serializer"],
"vars": ["Var"], "vars": ["Var", "field", "Field"],
} }
_SUBMODULES: set[str] = { _SUBMODULES: set[str] = {
"components", "components",
"event",
"app", "app",
"style", "style",
"admin", "admin",

View File

@ -11,7 +11,6 @@ from . import base as base
from . import compiler as compiler from . import compiler as compiler
from . import components as components from . import components as components
from . import config as config from . import config as config
from . import event as event
from . import model as model from . import model as model
from . import style as style from . import style as style
from . import testing as testing from . import testing as testing
@ -20,6 +19,7 @@ from . import vars as vars
from .admin import AdminDash as AdminDash from .admin import AdminDash as AdminDash
from .app import App as App from .app import App as App
from .app import UploadFile as UploadFile from .app import UploadFile as UploadFile
from .assets import asset as asset
from .base import Base as Base from .base import Base as Base
from .components import el as el from .components import el as el
from .components import lucide as lucide from .components import lucide as lucide
@ -153,19 +153,24 @@ from .components.suneditor import editor as editor
from .config import Config as Config from .config import Config as Config
from .config import DBConfig as DBConfig from .config import DBConfig as DBConfig
from .constants import Env as Env from .constants import Env as Env
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 background as background
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
from .event import clear_session_storage as clear_session_storage from .event import clear_session_storage as clear_session_storage
from .event import console_log as console_log from .event import console_log as console_log
from .event import download as download from .event import download as download
from .event import event as event
from .event import noop as noop
from .event import prevent_default as prevent_default from .event import prevent_default as prevent_default
from .event import redirect as redirect from .event import redirect as redirect
from .event import remove_cookie as remove_cookie from .event import remove_cookie as remove_cookie
from .event import remove_local_storage as remove_local_storage from .event import remove_local_storage as remove_local_storage
from .event import remove_session_storage as remove_session_storage from .event import remove_session_storage as remove_session_storage
from .event import run_script as run_script
from .event import scroll_to as scroll_to from .event import scroll_to as scroll_to
from .event import set_clipboard as set_clipboard from .event import set_clipboard as set_clipboard
from .event import set_focus as set_focus from .event import set_focus as set_focus
@ -174,22 +179,28 @@ from .event import stop_propagation as stop_propagation
from .event import upload_files as upload_files from .event import upload_files as upload_files
from .event import window_alert as window_alert from .event import window_alert as window_alert
from .experimental import _x as _x from .experimental import _x as _x
from .istate.storage import Cookie as Cookie
from .istate.storage import LocalStorage as LocalStorage
from .istate.storage import SessionStorage as SessionStorage
from .istate.wrappers import get_state as get_state
from .middleware import Middleware as Middleware from .middleware import Middleware as Middleware
from .middleware import middleware as middleware from .middleware import middleware as middleware
from .model import Model as Model from .model import Model as Model
from .model import asession as asession
from .model import session as session from .model import session as session
from .page import page as page from .page import page as page
from .state import ComponentState as ComponentState from .state import ComponentState as ComponentState
from .state import Cookie as Cookie
from .state import LocalStorage as LocalStorage
from .state import SessionStorage as SessionStorage
from .state import State as State from .state import State as State
from .state import dynamic as dynamic
from .state import var as var from .state import var as var
from .style import Style as Style from .style import Style as Style
from .style import toggle_color_mode as toggle_color_mode from .style import toggle_color_mode as toggle_color_mode
from .utils.imports import ImportDict as ImportDict
from .utils.imports import ImportVar as ImportVar from .utils.imports import ImportVar as ImportVar
from .utils.serializers import serializer as serializer from .utils.serializers import serializer as serializer
from .vars import Field as Field
from .vars import Var as Var from .vars import Var as Var
from .vars import field as field
del compat del compat
RADIX_THEMES_MAPPING: dict RADIX_THEMES_MAPPING: dict

View File

@ -6,23 +6,26 @@ import asyncio
import concurrent.futures import concurrent.futures
import contextlib import contextlib
import copy import copy
import dataclasses
import functools import functools
import inspect import inspect
import io import io
import json import json
import multiprocessing import multiprocessing
import os
import platform import platform
import sys import sys
import traceback import traceback
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from types import SimpleNamespace
from typing import ( from typing import (
TYPE_CHECKING,
Any, Any,
AsyncIterator, AsyncIterator,
Callable, Callable,
Coroutine, Coroutine,
Dict, Dict,
Generic,
List, List,
Optional, Optional,
Set, Set,
@ -44,10 +47,9 @@ from starlette_admin.contrib.sqla.view import ModelView
from reflex import constants from reflex import constants
from reflex.admin import AdminDash from reflex.admin import AdminDash
from reflex.app_mixins import AppMixin, LifespanMixin, MiddlewareMixin from reflex.app_mixins import AppMixin, LifespanMixin, MiddlewareMixin
from reflex.base import Base
from reflex.compiler import compiler from reflex.compiler import compiler
from reflex.compiler import utils as compiler_utils from reflex.compiler import utils as compiler_utils
from reflex.compiler.compiler import ExecutorSafeFunctions from reflex.compiler.compiler import ExecutorSafeFunctions, compile_theme
from reflex.components.base.app_wrap import AppWrap from reflex.components.base.app_wrap import AppWrap
from reflex.components.base.error_boundary import ErrorBoundary from reflex.components.base.error_boundary import ErrorBoundary
from reflex.components.base.fragment import Fragment from reflex.components.base.fragment import Fragment
@ -64,12 +66,19 @@ from reflex.components.core.client_side_routing import (
) )
from reflex.components.core.upload import Upload, get_upload_dir from reflex.components.core.upload import Upload, get_upload_dir
from reflex.components.radix import themes from reflex.components.radix import themes
from reflex.config import get_config from reflex.config import environment, get_config
from reflex.event import Event, EventHandler, EventSpec, window_alert from reflex.event import (
from reflex.model import Model, get_db_status BASE_STATE,
from reflex.page import ( Event,
DECORATED_PAGES, EventHandler,
EventSpec,
EventType,
IndividualEventType,
get_hydrate_event,
window_alert,
) )
from reflex.model import Model, get_db_status
from reflex.page import DECORATED_PAGES
from reflex.route import ( from reflex.route import (
get_route_args, get_route_args,
replace_brackets_with_keywords, replace_brackets_with_keywords,
@ -85,9 +94,12 @@ from reflex.state import (
code_uses_state_contexts, code_uses_state_contexts,
) )
from reflex.utils import codespaces, console, exceptions, format, prerequisites, types from reflex.utils import codespaces, console, exceptions, format, prerequisites, types
from reflex.utils.exec import is_prod_mode, is_testing_env, should_skip_compile from reflex.utils.exec import is_prod_mode, is_testing_env
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
if TYPE_CHECKING:
from reflex.vars import Var
# Define custom types. # Define custom types.
ComponentCallable = Callable[[], Component] ComponentCallable = Callable[[], Component]
Reducer = Callable[[Event], Coroutine[Any, Any, StateUpdate]] Reducer = Callable[[Event], Coroutine[Any, Any, StateUpdate]]
@ -170,7 +182,23 @@ class OverlayFragment(Fragment):
pass pass
class App(MiddlewareMixin, LifespanMixin, Base): @dataclasses.dataclass(
frozen=True,
)
class UnevaluatedPage(Generic[BASE_STATE]):
"""An uncompiled page."""
component: Union[Component, ComponentCallable]
route: str
title: Union[Var, str, None]
description: Union[Var, str, None]
image: str
on_load: Union[EventType[[], BASE_STATE], None]
meta: List[Dict[str, str]]
@dataclasses.dataclass()
class App(MiddlewareMixin, LifespanMixin):
"""The main Reflex app that encapsulates the backend and frontend. """The main Reflex app that encapsulates the backend and frontend.
Every Reflex app needs an app defined in its main module. Every Reflex app needs an app defined in its main module.
@ -192,24 +220,26 @@ class App(MiddlewareMixin, LifespanMixin, Base):
""" """
# The global [theme](https://reflex.dev/docs/styling/theming/#theme) for the entire app. # The global [theme](https://reflex.dev/docs/styling/theming/#theme) for the entire app.
theme: Optional[Component] = themes.theme(accent_color="blue") theme: Optional[Component] = dataclasses.field(
default_factory=lambda: themes.theme(accent_color="blue")
)
# The [global style](https://reflex.dev/docs/styling/overview/#global-styles}) for the app. # The [global style](https://reflex.dev/docs/styling/overview/#global-styles}) for the app.
style: ComponentStyle = {} style: ComponentStyle = dataclasses.field(default_factory=dict)
# A list of URLs to [stylesheets](https://reflex.dev/docs/styling/custom-stylesheets/) to include in the app. # A list of URLs to [stylesheets](https://reflex.dev/docs/styling/custom-stylesheets/) to include in the app.
stylesheets: List[str] = [] stylesheets: List[str] = dataclasses.field(default_factory=list)
# A component that is present on every page (defaults to the Connection Error banner). # A component that is present on every page (defaults to the Connection Error banner).
overlay_component: Optional[Union[Component, ComponentCallable]] = ( overlay_component: Optional[Union[Component, ComponentCallable]] = (
default_overlay_component() dataclasses.field(default_factory=default_overlay_component)
) )
# Error boundary component to wrap the app with. # Error boundary component to wrap the app with.
error_boundary: Optional[ComponentCallable] = default_error_boundary error_boundary: Optional[ComponentCallable] = default_error_boundary
# Components to add to the head of every page. # Components to add to the head of every page.
head_components: List[Component] = [] head_components: List[Component] = dataclasses.field(default_factory=list)
# The Socket.IO AsyncServer instance. # The Socket.IO AsyncServer instance.
sio: Optional[AsyncServer] = None sio: Optional[AsyncServer] = None
@ -220,8 +250,13 @@ class App(MiddlewareMixin, LifespanMixin, Base):
# Attributes to add to the html root tag of every page. # Attributes to add to the html root tag of every page.
html_custom_attrs: Optional[Dict[str, str]] = None html_custom_attrs: Optional[Dict[str, str]] = None
# A map from a route to an unevaluated page. PRIVATE.
unevaluated_pages: Dict[str, UnevaluatedPage] = dataclasses.field(
default_factory=dict
)
# A map from a page route to the component to render. Users should use `add_page`. PRIVATE. # A map from a page route to the component to render. Users should use `add_page`. PRIVATE.
pages: Dict[str, Component] = {} pages: Dict[str, Component] = dataclasses.field(default_factory=dict)
# The backend API object. PRIVATE. # The backend API object. PRIVATE.
api: FastAPI = None # type: ignore api: FastAPI = None # type: ignore
@ -233,7 +268,9 @@ class App(MiddlewareMixin, LifespanMixin, Base):
_state_manager: Optional[StateManager] = None _state_manager: Optional[StateManager] = None
# Mapping from a route to event handlers to trigger when the page loads. PRIVATE. # Mapping from a route to event handlers to trigger when the page loads. PRIVATE.
load_events: Dict[str, List[Union[EventHandler, EventSpec]]] = {} load_events: Dict[str, List[IndividualEventType[[], Any]]] = dataclasses.field(
default_factory=dict
)
# Admin dashboard to view and manage the database. PRIVATE. # Admin dashboard to view and manage the database. PRIVATE.
admin_dash: Optional[AdminDash] = None admin_dash: Optional[AdminDash] = None
@ -242,7 +279,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
event_namespace: Optional[EventNamespace] = None event_namespace: Optional[EventNamespace] = None
# Background tasks that are currently running. PRIVATE. # Background tasks that are currently running. PRIVATE.
background_tasks: Set[asyncio.Task] = set() background_tasks: Set[asyncio.Task] = dataclasses.field(default_factory=set)
# Frontend Error Handler Function # Frontend Error Handler Function
frontend_exception_handler: Callable[[Exception], None] = ( frontend_exception_handler: Callable[[Exception], None] = (
@ -254,23 +291,14 @@ class App(MiddlewareMixin, LifespanMixin, Base):
[Exception], Union[EventSpec, List[EventSpec], None] [Exception], Union[EventSpec, List[EventSpec], None]
] = default_backend_exception_handler ] = default_backend_exception_handler
def __init__(self, **kwargs): def __post_init__(self):
"""Initialize the app. """Initialize the app.
Args:
**kwargs: Kwargs to initialize the app with.
Raises: Raises:
ValueError: If the event namespace is not provided in the config. ValueError: If the event namespace is not provided in the config.
Also, if there are multiple client subclasses of rx.BaseState(Subclasses of rx.BaseState should consist Also, if there are multiple client subclasses of rx.BaseState(Subclasses of rx.BaseState should consist
of the DefaultState and the client app state). of the DefaultState and the client app state).
""" """
if "connect_error_component" in kwargs:
raise ValueError(
"`connect_error_component` is deprecated, use `overlay_component` instead"
)
super().__init__(**kwargs)
# Special case to allow test cases have multiple subclasses of rx.BaseState. # Special case to allow test cases have multiple subclasses of rx.BaseState.
if not is_testing_env() and BaseState.__subclasses__() != [State]: if not is_testing_env() and BaseState.__subclasses__() != [State]:
# Only rx.State is allowed as Base State subclass. # Only rx.State is allowed as Base State subclass.
@ -336,6 +364,11 @@ class App(MiddlewareMixin, LifespanMixin, Base):
max_http_buffer_size=constants.POLLING_MAX_HTTP_BUFFER_SIZE, max_http_buffer_size=constants.POLLING_MAX_HTTP_BUFFER_SIZE,
ping_interval=constants.Ping.INTERVAL, ping_interval=constants.Ping.INTERVAL,
ping_timeout=constants.Ping.TIMEOUT, ping_timeout=constants.Ping.TIMEOUT,
json=SimpleNamespace(
dumps=staticmethod(format.json_dumps),
loads=staticmethod(json.loads),
),
transports=["websocket"],
) )
elif getattr(self.sio, "async_mode", "") != "asgi": elif getattr(self.sio, "async_mode", "") != "asgi":
raise RuntimeError( raise RuntimeError(
@ -381,8 +414,8 @@ class App(MiddlewareMixin, LifespanMixin, Base):
def _add_optional_endpoints(self): def _add_optional_endpoints(self):
"""Add optional api endpoints (_upload).""" """Add optional api endpoints (_upload)."""
# To upload files.
if Upload.is_used: if Upload.is_used:
# To upload files.
self.api.post(str(constants.Endpoint.UPLOAD))(upload(self)) self.api.post(str(constants.Endpoint.UPLOAD))(upload(self))
# To access uploaded files. # To access uploaded files.
@ -403,7 +436,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
allow_credentials=True, allow_credentials=True,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],
allow_origins=["*"], allow_origins=get_config().cors_allowed_origins,
) )
@property @property
@ -431,36 +464,21 @@ class App(MiddlewareMixin, LifespanMixin, Base):
The generated component. The generated component.
Raises: Raises:
VarOperationTypeError: When an invalid component var related function is passed.
TypeError: When an invalid component function is passed.
exceptions.MatchTypeError: If the return types of match cases in rx.match are different. exceptions.MatchTypeError: If the return types of match cases in rx.match are different.
""" """
from reflex.utils.exceptions import VarOperationTypeError
try: try:
return component if isinstance(component, Component) else component() return component if isinstance(component, Component) else component()
except exceptions.MatchTypeError: except exceptions.MatchTypeError:
raise raise
except TypeError as e:
message = str(e)
if "Var" in message:
raise VarOperationTypeError(
"You may be trying to use an invalid Python function on a state var. "
"When referencing a var inside your render code, only limited var operations are supported. "
"See the var operation docs here: https://reflex.dev/docs/vars/var-operations/"
) from e
raise e
def add_page( def add_page(
self, self,
component: Component | ComponentCallable, component: Component | ComponentCallable | None = None,
route: str | None = None, route: str | None = None,
title: str | None = None, title: str | Var | None = None,
description: str | None = None, description: str | Var | None = None,
image: str = constants.DefaultPage.IMAGE, image: str = constants.DefaultPage.IMAGE,
on_load: ( on_load: EventType[[], BASE_STATE] | None = None,
EventHandler | EventSpec | list[EventHandler | EventSpec] | None
) = None,
meta: list[dict[str, str]] = constants.DefaultPage.META_LIST, meta: list[dict[str, str]] = constants.DefaultPage.META_LIST,
): ):
"""Add a page to the app. """Add a page to the app.
@ -478,33 +496,49 @@ class App(MiddlewareMixin, LifespanMixin, Base):
meta: The metadata of the page. meta: The metadata of the page.
Raises: Raises:
ValueError: When the specified route name already exists. PageValueError: When the component is not set for a non-404 page.
RouteValueError: When the specified route name already exists.
""" """
# If the route is not set, get it from the callable. # If the route is not set, get it from the callable.
if route is None: if route is None:
if not isinstance(component, Callable): if not isinstance(component, Callable):
raise ValueError("Route must be set if component is not a callable.") raise exceptions.RouteValueError(
"Route must be set if component is not a callable."
)
# Format the route. # Format the route.
route = format.format_route(component.__name__) route = format.format_route(component.__name__)
else: else:
route = format.format_route(route, format_case=False) route = format.format_route(route, format_case=False)
if route == constants.Page404.SLUG:
if component is None:
component = Default404Page.create()
component = wait_for_client_redirect(self._generate_component(component))
title = title or constants.Page404.TITLE
description = description or constants.Page404.DESCRIPTION
image = image or constants.Page404.IMAGE
else:
if component is None:
raise exceptions.PageValueError(
"Component must be set for a non-404 page."
)
# Check if the route given is valid # Check if the route given is valid
verify_route_validity(route) verify_route_validity(route)
if route in self.pages and os.getenv(constants.RELOAD_CONFIG): if route in self.unevaluated_pages and environment.RELOAD_CONFIG.is_set():
# when the app is reloaded(typically for app harness tests), we should maintain # when the app is reloaded(typically for app harness tests), we should maintain
# the latest render function of a route.This applies typically to decorated pages # the latest render function of a route.This applies typically to decorated pages
# since they are only added when app._compile is called. # since they are only added when app._compile is called.
self.pages.pop(route) self.unevaluated_pages.pop(route)
if route in self.pages: if route in self.unevaluated_pages:
route_name = ( route_name = (
f"`{route}` or `/`" f"`{route}` or `/`"
if route == constants.PageNames.INDEX_ROUTE if route == constants.PageNames.INDEX_ROUTE
else f"`{route}`" else f"`{route}`"
) )
raise ValueError( raise exceptions.RouteValueError(
f"Duplicate page route {route_name} already exists. Make sure you do not have two" f"Duplicate page route {route_name} already exists. Make sure you do not have two"
f" pages with the same route" f" pages with the same route"
) )
@ -514,59 +548,39 @@ class App(MiddlewareMixin, LifespanMixin, Base):
state = self.state if self.state else State state = self.state if self.state else State
state.setup_dynamic_args(get_route_args(route)) state.setup_dynamic_args(get_route_args(route))
# Generate the component if it is a callable. if on_load:
component = self._generate_component(component) self.load_events[route] = (
on_load if isinstance(on_load, list) else [on_load]
)
# unpack components that return tuples in an rx.fragment. self.unevaluated_pages[route] = UnevaluatedPage(
if isinstance(component, tuple): component=component,
component = Fragment.create(*component) route=route,
title=title,
# Ensure state is enabled if this page uses state. description=description,
if self.state is None: image=image,
if on_load or component._has_stateful_event_triggers(): on_load=on_load,
self._enable_state() meta=meta,
else:
for var in component._get_vars(include_children=True):
var_data = var._get_all_var_data()
if not var_data:
continue
if not var_data.state:
continue
self._enable_state()
break
component = OverlayFragment.create(component)
meta_args = {
"title": (
title
if title is not None
else format.make_default_page_title(get_config().app_name, route)
),
"image": image,
"meta": meta,
}
if description is not None:
meta_args["description"] = description
# Add meta information to the component.
compiler_utils.add_meta(
component,
**meta_args,
) )
def _compile_page(self, route: str):
"""Compile a page.
Args:
route: The route of the page to compile.
"""
component, enable_state = compiler.compile_unevaluated_page(
route, self.unevaluated_pages[route], self.state, self.style, self.theme
)
if enable_state:
self._enable_state()
# Add the page. # Add the page.
self._check_routes_conflict(route) self._check_routes_conflict(route)
self.pages[route] = component self.pages[route] = component
# Add the load events. def get_load_events(self, route: str) -> list[IndividualEventType[[], Any]]:
if on_load:
if not isinstance(on_load, list):
on_load = [on_load]
self.load_events[route] = on_load
def get_load_events(self, route: str) -> list[EventHandler | EventSpec]:
"""Get the load events for a route. """Get the load events for a route.
Args: Args:
@ -625,9 +639,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
title: str = constants.Page404.TITLE, title: str = constants.Page404.TITLE,
image: str = constants.Page404.IMAGE, image: str = constants.Page404.IMAGE,
description: str = constants.Page404.DESCRIPTION, description: str = constants.Page404.DESCRIPTION,
on_load: ( on_load: EventType[[], BASE_STATE] | None = None,
EventHandler | EventSpec | list[EventHandler | EventSpec] | None
) = None,
meta: list[dict[str, str]] = constants.DefaultPage.META_LIST, meta: list[dict[str, str]] = constants.DefaultPage.META_LIST,
): ):
"""Define a custom 404 page for any url having no match. """Define a custom 404 page for any url having no match.
@ -643,10 +655,14 @@ class App(MiddlewareMixin, LifespanMixin, Base):
on_load: The event handler(s) that will be called each time the page load. on_load: The event handler(s) that will be called each time the page load.
meta: The metadata of the page. meta: The metadata of the page.
""" """
if component is None: console.deprecate(
component = Default404Page.create() feature_name="App.add_custom_404_page",
reason=f"Use app.add_page(component, route='/{constants.Page404.SLUG}') instead.",
deprecation_version="0.6.7",
removal_version="0.8.0",
)
self.add_page( self.add_page(
component=wait_for_client_redirect(self._generate_component(component)), component=component,
route=constants.Page404.SLUG, route=constants.Page404.SLUG,
title=title or constants.Page404.TITLE, title=title or constants.Page404.TITLE,
image=image or constants.Page404.IMAGE, image=image or constants.Page404.IMAGE,
@ -692,7 +708,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
for i, tags in imports.items() for i, tags in imports.items()
if i not in constants.PackageJson.DEPENDENCIES if i not in constants.PackageJson.DEPENDENCIES
and i not in constants.PackageJson.DEV_DEPENDENCIES and i not in constants.PackageJson.DEV_DEPENDENCIES
and not any(i.startswith(prefix) for prefix in ["/", ".", "next/"]) and not any(i.startswith(prefix) for prefix in ["/", "$/", ".", "next/"])
and i != "" and i != ""
and any(tag.install for tag in tags) and any(tag.install for tag in tags)
} }
@ -731,7 +747,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
Whether the app should be compiled. Whether the app should be compiled.
""" """
# Check the environment variable. # Check the environment variable.
if should_skip_compile(): if environment.REFLEX_SKIP_COMPILE.get():
return False return False
nocompile = prerequisites.get_web_dir() / constants.NOCOMPILE_FILE nocompile = prerequisites.get_web_dir() / constants.NOCOMPILE_FILE
@ -840,12 +856,31 @@ class App(MiddlewareMixin, LifespanMixin, Base):
""" """
from reflex.utils.exceptions import ReflexRuntimeError from reflex.utils.exceptions import ReflexRuntimeError
self.pages = {}
def get_compilation_time() -> str: def get_compilation_time() -> str:
return str(datetime.now().time()).split(".")[0] return str(datetime.now().time()).split(".")[0]
# Render a default 404 page if the user didn't supply one # Render a default 404 page if the user didn't supply one
if constants.Page404.SLUG not in self.pages: if constants.Page404.SLUG not in self.unevaluated_pages:
self.add_custom_404_page() self.add_page(route=constants.Page404.SLUG)
# Fix up the style.
self.style = evaluate_style_namespaces(self.style)
# Add the app wrappers.
app_wrappers: Dict[tuple[int, str], Component] = {
# Default app wrap component renders {children}
(0, "AppWrap"): AppWrap.create()
}
if self.theme is not None:
# If a theme component was provided, wrap the app with it
app_wrappers[(20, "Theme")] = self.theme
for route in self.unevaluated_pages:
console.debug(f"Evaluating page: {route}")
self._compile_page(route)
# Add the optional endpoints (_upload) # Add the optional endpoints (_upload)
self._add_optional_endpoints() self._add_optional_endpoints()
@ -881,28 +916,15 @@ class App(MiddlewareMixin, LifespanMixin, Base):
# Store the compile results. # Store the compile results.
compile_results = [] compile_results = []
# Add the app wrappers.
app_wrappers: Dict[tuple[int, str], Component] = {
# Default app wrap component renders {children}
(0, "AppWrap"): AppWrap.create()
}
if self.theme is not None:
# If a theme component was provided, wrap the app with it
app_wrappers[(20, "Theme")] = self.theme
progress.advance(task) progress.advance(task)
# Fix up the style.
self.style = evaluate_style_namespaces(self.style)
# Track imports and custom components found. # Track imports and custom components found.
all_imports = {} all_imports = {}
custom_components = set() custom_components = set()
for _route, component in self.pages.items(): # This has to happen before compiling stateful components as that
# Merge the component style with the app style. # prevents recursive functions from reaching all components.
component._add_style_recursive(self.style, self.theme) for component in self.pages.values():
# Add component._get_all_imports() to all_imports. # Add component._get_all_imports() to all_imports.
all_imports.update(component._get_all_imports()) all_imports.update(component._get_all_imports())
@ -912,8 +934,6 @@ class App(MiddlewareMixin, LifespanMixin, Base):
# Add the custom components from the page to the set. # Add the custom components from the page to the set.
custom_components |= component._get_all_custom_components() custom_components |= component._get_all_custom_components()
progress.advance(task)
# Perform auto-memoization of stateful components. # Perform auto-memoization of stateful components.
( (
stateful_components_path, stateful_components_path,
@ -931,6 +951,8 @@ class App(MiddlewareMixin, LifespanMixin, Base):
) )
compile_results.append((stateful_components_path, stateful_components_code)) compile_results.append((stateful_components_path, stateful_components_code))
progress.advance(task)
# Compile the root document before fork. # Compile the root document before fork.
compile_results.append( compile_results.append(
compiler.compile_document_root( compiler.compile_document_root(
@ -940,77 +962,49 @@ class App(MiddlewareMixin, LifespanMixin, Base):
) )
) )
# Compile the contexts before fork.
compile_results.append(
compiler.compile_contexts(self.state, self.theme),
)
# Fix #2992 by removing the top-level appearance prop
if self.theme is not None:
self.theme.appearance = None
app_root = self._app_root(app_wrappers=app_wrappers)
progress.advance(task) progress.advance(task)
# Prepopulate the global ExecutorSafeFunctions class with input data required by the compile functions.
# This is required for multiprocessing to work, in presence of non-picklable inputs.
for route, component in zip(self.pages, page_components):
ExecutorSafeFunctions.COMPILE_PAGE_ARGS_BY_ROUTE[route] = (
route,
component,
self.state,
)
ExecutorSafeFunctions.COMPILE_APP_APP_ROOT = app_root
ExecutorSafeFunctions.CUSTOM_COMPONENTS = custom_components
ExecutorSafeFunctions.STYLE = self.style
# Use a forking process pool, if possible. Much faster, especially for large sites. # Use a forking process pool, if possible. Much faster, especially for large sites.
# Fallback to ThreadPoolExecutor as something that will always work. # Fallback to ThreadPoolExecutor as something that will always work.
executor = None executor = None
if ( if (
platform.system() in ("Linux", "Darwin") platform.system() in ("Linux", "Darwin")
and os.environ.get("REFLEX_COMPILE_PROCESSES") is not None and (number_of_processes := environment.REFLEX_COMPILE_PROCESSES.get())
is not None
): ):
executor = concurrent.futures.ProcessPoolExecutor( executor = concurrent.futures.ProcessPoolExecutor(
max_workers=int(os.environ.get("REFLEX_COMPILE_PROCESSES", 0)) or None, max_workers=number_of_processes or None,
mp_context=multiprocessing.get_context("fork"), mp_context=multiprocessing.get_context("fork"),
) )
else: else:
executor = concurrent.futures.ThreadPoolExecutor( executor = concurrent.futures.ThreadPoolExecutor(
max_workers=int(os.environ.get("REFLEX_COMPILE_THREADS", 0)) or None, max_workers=environment.REFLEX_COMPILE_THREADS.get() or None
) )
for route, component in zip(self.pages, page_components):
ExecutorSafeFunctions.COMPONENTS[route] = component
ExecutorSafeFunctions.STATE = self.state
with executor: with executor:
result_futures = [] result_futures = []
custom_components_future = None
def _mark_complete(_=None):
progress.advance(task)
def _submit_work(fn, *args, **kwargs): def _submit_work(fn, *args, **kwargs):
f = executor.submit(fn, *args, **kwargs) f = executor.submit(fn, *args, **kwargs)
f.add_done_callback(_mark_complete)
result_futures.append(f) result_futures.append(f)
# Compile all page components. # Compile the pre-compiled pages.
for route in self.pages: for route in self.pages:
_submit_work(ExecutorSafeFunctions.compile_page, route) _submit_work(
ExecutorSafeFunctions.compile_page,
# Compile the app wrapper. route,
_submit_work(ExecutorSafeFunctions.compile_app) )
# Compile the custom components.
custom_components_future = executor.submit(
ExecutorSafeFunctions.compile_custom_components,
)
custom_components_future.add_done_callback(_mark_complete)
# Compile the root stylesheet with base styles. # Compile the root stylesheet with base styles.
_submit_work(compiler.compile_root_stylesheet, self.stylesheets) _submit_work(compiler.compile_root_stylesheet, self.stylesheets)
# Compile the theme. # Compile the theme.
_submit_work(ExecutorSafeFunctions.compile_theme) _submit_work(compile_theme, self.style)
# Compile the Tailwind config. # Compile the Tailwind config.
if config.tailwind is not None: if config.tailwind is not None:
@ -1024,21 +1018,37 @@ class App(MiddlewareMixin, LifespanMixin, Base):
# Wait for all compilation tasks to complete. # Wait for all compilation tasks to complete.
for future in concurrent.futures.as_completed(result_futures): for future in concurrent.futures.as_completed(result_futures):
compile_results.append(future.result()) compile_results.append(future.result())
progress.advance(task)
# Special case for custom_components, since we need the compiled imports app_root = self._app_root(app_wrappers=app_wrappers)
# to install proper frontend packages.
(
*custom_components_result,
custom_components_imports,
) = custom_components_future.result()
compile_results.append(custom_components_result)
all_imports.update(custom_components_imports)
# Get imports from AppWrap components. # Get imports from AppWrap components.
all_imports.update(app_root._get_all_imports()) all_imports.update(app_root._get_all_imports())
progress.advance(task) progress.advance(task)
# Compile the contexts.
compile_results.append(
compiler.compile_contexts(self.state, self.theme),
)
if self.theme is not None:
# Fix #2992 by removing the top-level appearance prop
self.theme.appearance = None
progress.advance(task)
# Compile the app root.
compile_results.append(
compiler.compile_app(app_root),
)
progress.advance(task)
# Compile custom components.
*custom_components_result, custom_components_imports = (
compiler.compile_components(custom_components)
)
compile_results.append(custom_components_result)
all_imports.update(custom_components_imports)
progress.advance(task) progress.advance(task)
progress.stop() progress.stop()
@ -1172,7 +1182,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
if hasattr(handler_fn, "__name__"): if hasattr(handler_fn, "__name__"):
_fn_name = handler_fn.__name__ _fn_name = handler_fn.__name__
else: else:
_fn_name = handler_fn.__class__.__name__ _fn_name = type(handler_fn).__name__
if isinstance(handler_fn, functools.partial): if isinstance(handler_fn, functools.partial):
raise ValueError( raise ValueError(
@ -1275,6 +1285,21 @@ async def process(
) )
# Get the state for the session exclusively. # Get the state for the session exclusively.
async with app.state_manager.modify_state(event.substate_token) as state: async with app.state_manager.modify_state(event.substate_token) as state:
# When this is a brand new instance of the state, signal the
# frontend to reload before processing it.
if (
not state.router_data
and event.name != get_hydrate_event(state)
and app.event_namespace is not None
):
await asyncio.create_task(
app.event_namespace.emit(
"reload",
data=event,
to=sid,
)
)
return
# re-assign only when the value is different # re-assign only when the value is different
if state.router_data != router_data: if state.router_data != router_data:
# assignment will recurse into substates and force recalculation of # assignment will recurse into substates and force recalculation of
@ -1405,7 +1430,7 @@ def upload(app: App):
if isinstance(func, EventHandler): if isinstance(func, EventHandler):
if func.is_background: if func.is_background:
raise UploadTypeError( raise UploadTypeError(
f"@rx.background is not supported for upload handler `{handler}`.", f"@rx.event(background=True) is not supported for upload handler `{handler}`.",
) )
func = func.fn func = func.fn
if isinstance(func, functools.partial): if isinstance(func, functools.partial):
@ -1478,10 +1503,10 @@ class EventNamespace(AsyncNamespace):
app: App app: App
# Keep a mapping between socket ID and client token. # Keep a mapping between socket ID and client token.
token_to_sid: dict[str, str] = {} token_to_sid: dict[str, str]
# Keep a mapping between client token and socket ID. # Keep a mapping between client token and socket ID.
sid_to_token: dict[str, str] = {} sid_to_token: dict[str, str]
def __init__(self, namespace: str, app: App): def __init__(self, namespace: str, app: App):
"""Initialize the event namespace. """Initialize the event namespace.
@ -1491,6 +1516,8 @@ class EventNamespace(AsyncNamespace):
app: The application object. app: The application object.
""" """
super().__init__(namespace) super().__init__(namespace)
self.token_to_sid = {}
self.sid_to_token = {}
self.app = app self.app = app
def on_connect(self, sid, environ): def on_connect(self, sid, environ):
@ -1521,7 +1548,7 @@ class EventNamespace(AsyncNamespace):
""" """
# Creating a task prevents the update from being blocked behind other coroutines. # Creating a task prevents the update from being blocked behind other coroutines.
await asyncio.create_task( await asyncio.create_task(
self.emit(str(constants.SocketEvent.EVENT), update.json(), to=sid) self.emit(str(constants.SocketEvent.EVENT), update, to=sid)
) )
async def on_event(self, sid, data): async def on_event(self, sid, data):
@ -1534,9 +1561,11 @@ class EventNamespace(AsyncNamespace):
sid: The Socket.IO session id. sid: The Socket.IO session id.
data: The event data. data: The event data.
""" """
fields = json.loads(data) fields = data
# Get the event. # Get the event.
event = Event(**{k: v for k, v in fields.items() if k != "handler"}) event = Event(
**{k: v for k, v in fields.items() if k not in ("handler", "event_actions")}
)
self.token_to_sid[event.token] = sid self.token_to_sid[event.token] = sid
self.sid_to_token[sid] = event.token self.sid_to_token[sid] = event.token

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import asyncio import asyncio
import contextlib import contextlib
import dataclasses
import functools import functools
import inspect import inspect
from typing import Callable, Coroutine, Set, Union from typing import Callable, Coroutine, Set, Union
@ -16,11 +17,14 @@ from reflex.utils.exceptions import InvalidLifespanTaskType
from .mixin import AppMixin from .mixin import AppMixin
@dataclasses.dataclass
class LifespanMixin(AppMixin): class LifespanMixin(AppMixin):
"""A Mixin that allow tasks to run during the whole app lifespan.""" """A Mixin that allow tasks to run during the whole app lifespan."""
# Lifespan tasks that are planned to run. # Lifespan tasks that are planned to run.
lifespan_tasks: Set[Union[asyncio.Task, Callable]] = set() lifespan_tasks: Set[Union[asyncio.Task, Callable]] = dataclasses.field(
default_factory=set
)
@contextlib.asynccontextmanager @contextlib.asynccontextmanager
async def _run_lifespan_tasks(self, app: FastAPI): async def _run_lifespan_tasks(self, app: FastAPI):

View File

@ -3,6 +3,7 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
import dataclasses
from typing import List from typing import List
from reflex.event import Event from reflex.event import Event
@ -12,11 +13,12 @@ from reflex.state import BaseState, StateUpdate
from .mixin import AppMixin from .mixin import AppMixin
@dataclasses.dataclass
class MiddlewareMixin(AppMixin): class MiddlewareMixin(AppMixin):
"""Middleware Mixin that allow to add middleware to the app.""" """Middleware Mixin that allow to add middleware to the app."""
# Middleware to add to the app. Users should use `add_middleware`. PRIVATE. # Middleware to add to the app. Users should use `add_middleware`. PRIVATE.
middleware: List[Middleware] = [] middleware: List[Middleware] = dataclasses.field(default_factory=list)
def _init_mixin(self): def _init_mixin(self):
self.middleware.append(HydrateMiddleware()) self.middleware.append(HydrateMiddleware())

View File

@ -1,9 +1,10 @@
"""Default mixin for all app mixins.""" """Default mixin for all app mixins."""
from reflex.base import Base import dataclasses
class AppMixin(Base): @dataclasses.dataclass
class AppMixin:
"""Define the base class for all app mixins.""" """Define the base class for all app mixins."""
def _init_mixin(self): def _init_mixin(self):

95
reflex/assets.py Normal file
View File

@ -0,0 +1,95 @@
"""Helper functions for adding assets to the app."""
import inspect
from pathlib import Path
from typing import Optional
from reflex import constants
from reflex.config import EnvironmentVariables
def asset(
path: str,
shared: bool = False,
subfolder: Optional[str] = None,
_stack_level: int = 1,
) -> str:
"""Add an asset to the app, either shared as a symlink or local.
Shared/External/Library assets:
Place the file next to your including python file.
Links the file to the app's external assets directory.
Example:
```python
# my_custom_javascript.js is a shared asset located next to the including python file.
rx.script(src=rx.asset(path="my_custom_javascript.js", shared=True))
rx.image(src=rx.asset(path="test_image.png", shared=True, subfolder="subfolder"))
```
Local/Internal assets:
Place the file in the app's assets/ directory.
Example:
```python
# local_image.png is an asset located in the app's assets/ directory. It cannot be shared when developing a library.
rx.image(src=rx.asset(path="local_image.png"))
```
Args:
path: The relative path of the asset.
subfolder: The directory to place the shared asset in.
shared: Whether to expose the asset to other apps.
_stack_level: The stack level to determine the calling file, defaults to
the immediate caller 1. When using rx.asset via a helper function,
increase this number for each helper function in the stack.
Raises:
FileNotFoundError: If the file does not exist.
ValueError: If subfolder is provided for local assets.
Returns:
The relative URL to the asset.
"""
assets = constants.Dirs.APP_ASSETS
backend_only = EnvironmentVariables.REFLEX_BACKEND_ONLY.get()
# Local asset handling
if not shared:
cwd = Path.cwd()
src_file_local = cwd / assets / path
if subfolder is not None:
raise ValueError("Subfolder is not supported for local assets.")
if not backend_only and not src_file_local.exists():
raise FileNotFoundError(f"File not found: {src_file_local}")
return f"/{path}"
# Shared asset handling
# Determine the file by which the asset is exposed.
frame = inspect.stack()[_stack_level]
calling_file = frame.filename
module = inspect.getmodule(frame[0])
assert module is not None
external = constants.Dirs.EXTERNAL_APP_ASSETS
src_file_shared = Path(calling_file).parent / path
if not src_file_shared.exists():
raise FileNotFoundError(f"File not found: {src_file_shared}")
caller_module_path = module.__name__.replace(".", "/")
subfolder = f"{caller_module_path}/{subfolder}" if subfolder else caller_module_path
# Symlink the asset to the app's external assets directory if running frontend.
if not backend_only:
# Create the asset folder in the currently compiling app.
asset_folder = Path.cwd() / assets / external / subfolder
asset_folder.mkdir(parents=True, exist_ok=True)
dst_file = asset_folder / path
if not dst_file.exists() and (
not dst_file.is_symlink() or dst_file.resolve() != src_file_shared.resolve()
):
dst_file.symlink_to(src_file_shared)
return f"/{external}/{subfolder}/{path}"

View File

@ -16,9 +16,6 @@ except ModuleNotFoundError:
from pydantic.fields import ModelField # type: ignore from pydantic.fields import ModelField # type: ignore
from reflex import constants
def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None: def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None:
"""Ensure that the field's name does not shadow an existing attribute of the model. """Ensure that the field's name does not shadow an existing attribute of the model.
@ -31,7 +28,8 @@ def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None
""" """
from reflex.utils.exceptions import VarNameError from reflex.utils.exceptions import VarNameError
reload = os.getenv(constants.RELOAD_CONFIG) == "True" # can't use reflex.config.environment here cause of circular import
reload = os.getenv("__RELOAD_CONFIG", "").lower() == "true"
for base in bases: for base in bases:
try: try:
if not reload and getattr(base, field_name, None): if not reload and getattr(base, field_name, None):
@ -132,8 +130,8 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
Returns: Returns:
The value of the field. The value of the field.
""" """
if isinstance(key, str) and key in self.__fields__: if isinstance(key, str):
# Seems like this function signature was wrong all along? # Seems like this function signature was wrong all along?
# If the user wants a field that we know of, get it and pass it off to _get_value # If the user wants a field that we know of, get it and pass it off to _get_value
key = getattr(self, key) return getattr(self, key, key)
return key return key

View File

@ -2,13 +2,13 @@
from __future__ import annotations from __future__ import annotations
import os
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Dict, Iterable, Optional, Type, Union from typing import TYPE_CHECKING, Dict, Iterable, Optional, Tuple, Type, Union
from reflex import constants from reflex import constants
from reflex.compiler import templates, utils from reflex.compiler import templates, utils
from reflex.components.base.fragment import Fragment
from reflex.components.component import ( from reflex.components.component import (
BaseComponent, BaseComponent,
Component, Component,
@ -16,7 +16,7 @@ from reflex.components.component import (
CustomComponent, CustomComponent,
StatefulComponent, StatefulComponent,
) )
from reflex.config import get_config from reflex.config import environment, get_config
from reflex.state import BaseState from reflex.state import BaseState
from reflex.style import SYSTEM_COLOR_MODE from reflex.style import SYSTEM_COLOR_MODE
from reflex.utils.exec import is_prod_mode from reflex.utils.exec import is_prod_mode
@ -40,6 +40,20 @@ def _compile_document_root(root: Component) -> str:
) )
def _normalize_library_name(lib: str) -> str:
"""Normalize the library name.
Args:
lib: The library name to normalize.
Returns:
The normalized library name.
"""
if lib == "react":
return "React"
return lib.replace("@", "").replace("/", "_").replace("-", "_")
def _compile_app(app_root: Component) -> str: def _compile_app(app_root: Component) -> str:
"""Compile the app template component. """Compile the app template component.
@ -49,10 +63,20 @@ def _compile_app(app_root: Component) -> str:
Returns: Returns:
The compiled app. The compiled app.
""" """
from reflex.components.dynamic import bundled_libraries
window_libraries = [
(_normalize_library_name(name), name) for name in bundled_libraries
] + [
("utils_context", f"$/{constants.Dirs.UTILS}/context"),
("utils_state", f"$/{constants.Dirs.UTILS}/state"),
]
return templates.APP_ROOT.render( return templates.APP_ROOT.render(
imports=utils.compile_imports(app_root._get_all_imports()), imports=utils.compile_imports(app_root._get_all_imports()),
custom_codes=app_root._get_all_custom_code(), custom_codes=app_root._get_all_custom_code(),
hooks={**app_root._get_all_hooks_internal(), **app_root._get_all_hooks()}, hooks={**app_root._get_all_hooks_internal(), **app_root._get_all_hooks()},
window_libraries=window_libraries,
render=app_root.render(), render=app_root.render(),
) )
@ -103,8 +127,8 @@ def _compile_contexts(state: Optional[Type[BaseState]], theme: Component | None)
def _compile_page( def _compile_page(
component: Component, component: BaseComponent,
state: Type[BaseState], state: Type[BaseState] | None,
) -> str: ) -> str:
"""Compile the component given the app state. """Compile the component given the app state.
@ -119,7 +143,7 @@ def _compile_page(
imports = utils.compile_imports(imports) imports = utils.compile_imports(imports)
# Compile the code to render the component. # Compile the code to render the component.
kwargs = {"state_name": state.get_name()} if state else {} kwargs = {"state_name": state.get_name()} if state is not None else {}
return templates.PAGE.render( return templates.PAGE.render(
imports=imports, imports=imports,
@ -171,7 +195,7 @@ def _compile_root_stylesheet(stylesheets: list[str]) -> str:
stylesheet_full_path = ( stylesheet_full_path = (
Path.cwd() / constants.Dirs.APP_ASSETS / stylesheet.strip("/") Path.cwd() / constants.Dirs.APP_ASSETS / stylesheet.strip("/")
) )
if not os.path.exists(stylesheet_full_path): if not stylesheet_full_path.exists():
raise FileNotFoundError( raise FileNotFoundError(
f"The stylesheet file {stylesheet_full_path} does not exist." f"The stylesheet file {stylesheet_full_path} does not exist."
) )
@ -205,7 +229,7 @@ def _compile_components(
""" """
imports = { imports = {
"react": [ImportVar(tag="memo")], "react": [ImportVar(tag="memo")],
f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="E"), ImportVar(tag="isTrue")], f"$/{constants.Dirs.STATE_PATH}": [ImportVar(tag="E"), ImportVar(tag="isTrue")],
} }
component_renders = [] component_renders = []
@ -292,7 +316,7 @@ def _compile_stateful_components(
# Don't import from the file that we're about to create. # Don't import from the file that we're about to create.
all_imports = utils.merge_imports(*all_import_dicts) all_imports = utils.merge_imports(*all_import_dicts)
all_imports.pop( all_imports.pop(
f"/{constants.Dirs.UTILS}/{constants.PageNames.STATEFUL_COMPONENTS}", None f"$/{constants.Dirs.UTILS}/{constants.PageNames.STATEFUL_COMPONENTS}", None
) )
return templates.STATEFUL_COMPONENTS.render( return templates.STATEFUL_COMPONENTS.render(
@ -401,7 +425,7 @@ def compile_contexts(
def compile_page( def compile_page(
path: str, component: Component, state: Type[BaseState] path: str, component: BaseComponent, state: Type[BaseState] | None
) -> tuple[str, str]: ) -> tuple[str, str]:
"""Compile a single page. """Compile a single page.
@ -503,7 +527,7 @@ def remove_tailwind_from_postcss() -> tuple[str, str]:
def purge_web_pages_dir(): def purge_web_pages_dir():
"""Empty out .web/pages directory.""" """Empty out .web/pages directory."""
if not is_prod_mode() and os.environ.get("REFLEX_PERSIST_WEB_DIR"): if not is_prod_mode() and environment.REFLEX_PERSIST_WEB_DIR.get():
# Skip purging the web directory in dev mode if REFLEX_PERSIST_WEB_DIR is set. # Skip purging the web directory in dev mode if REFLEX_PERSIST_WEB_DIR is set.
return return
@ -511,6 +535,81 @@ def purge_web_pages_dir():
utils.empty_dir(get_web_dir() / constants.Dirs.PAGES, keep_files=["_app.js"]) utils.empty_dir(get_web_dir() / constants.Dirs.PAGES, keep_files=["_app.js"])
if TYPE_CHECKING:
from reflex.app import UnevaluatedPage
def compile_unevaluated_page(
route: str,
page: UnevaluatedPage,
state: Type[BaseState] | None = None,
style: ComponentStyle | None = None,
theme: Component | None = None,
) -> Tuple[Component, bool]:
"""Compiles an uncompiled page into a component and adds meta information.
Args:
route: The route of the page.
page: The uncompiled page object.
state: The state of the app.
style: The style of the page.
theme: The theme of the page.
Returns:
The compiled component and whether state should be enabled.
"""
# Generate the component if it is a callable.
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)
enable_state = False
# Ensure state is enabled if this page uses state.
if state is None:
if page.on_load or component._has_stateful_event_triggers():
enable_state = True
else:
for var in component._get_vars(include_children=True):
var_data = var._get_all_var_data()
if not var_data:
continue
if not var_data.state:
continue
enable_state = True
break
from reflex.app import OverlayFragment
from reflex.utils.format import make_default_page_title
component = OverlayFragment.create(component)
meta_args = {
"title": (
page.title
if page.title is not None
else make_default_page_title(get_config().app_name, route)
),
"image": page.image,
"meta": page.meta,
}
if page.description is not None:
meta_args["description"] = page.description
# Add meta information to the component.
utils.add_meta(
component,
**meta_args,
)
return component, enable_state
class ExecutorSafeFunctions: class ExecutorSafeFunctions:
"""Helper class to allow parallelisation of parts of the compilation process. """Helper class to allow parallelisation of parts of the compilation process.
@ -536,13 +635,12 @@ class ExecutorSafeFunctions:
""" """
COMPILE_PAGE_ARGS_BY_ROUTE = {} COMPONENTS: Dict[str, BaseComponent] = {}
COMPILE_APP_APP_ROOT: Component | None = None UNCOMPILED_PAGES: Dict[str, UnevaluatedPage] = {}
CUSTOM_COMPONENTS: set[CustomComponent] | None = None STATE: Optional[Type[BaseState]] = None
STYLE: ComponentStyle | None = None
@classmethod @classmethod
def compile_page(cls, route: str): def compile_page(cls, route: str) -> tuple[str, str]:
"""Compile a page. """Compile a page.
Args: Args:
@ -551,46 +649,45 @@ class ExecutorSafeFunctions:
Returns: Returns:
The path and code of the compiled page. The path and code of the compiled page.
""" """
return compile_page(*cls.COMPILE_PAGE_ARGS_BY_ROUTE[route]) return compile_page(route, cls.COMPONENTS[route], cls.STATE)
@classmethod @classmethod
def compile_app(cls): def compile_unevaluated_page(
"""Compile the app. cls,
route: str,
style: ComponentStyle,
theme: Component | None,
) -> tuple[str, Component, tuple[str, str]]:
"""Compile an unevaluated page.
Args:
route: The route of the page to compile.
style: The style of the page.
theme: The theme of the page.
Returns: Returns:
The path and code of the compiled app. The route, compiled component, and compiled page.
Raises:
ValueError: If the app root is not set.
""" """
if cls.COMPILE_APP_APP_ROOT is None: component, enable_state = compile_unevaluated_page(
raise ValueError("COMPILE_APP_APP_ROOT should be set") route, cls.UNCOMPILED_PAGES[route]
return compile_app(cls.COMPILE_APP_APP_ROOT) )
component = component if isinstance(component, Component) else component()
component._add_style_recursive(style, theme)
return route, component, compile_page(route, component, cls.STATE)
@classmethod @classmethod
def compile_custom_components(cls): def compile_theme(cls, style: ComponentStyle | None) -> tuple[str, str]:
"""Compile the custom components.
Returns:
The path and code of the compiled custom components.
Raises:
ValueError: If the custom components are not set.
"""
if cls.CUSTOM_COMPONENTS is None:
raise ValueError("CUSTOM_COMPONENTS should be set")
return compile_components(cls.CUSTOM_COMPONENTS)
@classmethod
def compile_theme(cls):
"""Compile the theme. """Compile the theme.
Args:
style: The style to compile.
Returns: Returns:
The path and code of the compiled theme. The path and code of the compiled theme.
Raises: Raises:
ValueError: If the style is not set. ValueError: If the style is not set.
""" """
if cls.STYLE is None: if style is None:
raise ValueError("STYLE should be set") raise ValueError("STYLE should be set")
return compile_theme(cls.STYLE) return compile_theme(style)

View File

@ -2,7 +2,6 @@
from __future__ import annotations from __future__ import annotations
import os
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
@ -29,7 +28,8 @@ from reflex.components.base import (
Title, Title,
) )
from reflex.components.component import Component, ComponentStyle, CustomComponent from reflex.components.component import Component, ComponentStyle, CustomComponent
from reflex.state import BaseState, Cookie, LocalStorage, SessionStorage from reflex.istate.storage import Cookie, LocalStorage, SessionStorage
from reflex.state import BaseState
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.imports import ImportVar, ParsedImportDict from reflex.utils.imports import ImportVar, ParsedImportDict
@ -83,6 +83,12 @@ def validate_imports(import_dict: ParsedImportDict):
f"{_import.tag}/{_import.alias}" if _import.alias else _import.tag f"{_import.tag}/{_import.alias}" if _import.alias else _import.tag
) )
if import_name in used_tags: if import_name in used_tags:
already_imported = used_tags[import_name]
if (already_imported[0] == "$" and already_imported[1:] == lib) or (
lib[0] == "$" and lib[1:] == already_imported
):
used_tags[import_name] = lib if lib[0] == "$" else already_imported
continue
raise ValueError( raise ValueError(
f"Can not compile, the tag {import_name} is used multiple time from {lib} and {used_tags[import_name]}" f"Can not compile, the tag {import_name} is used multiple time from {lib} and {used_tags[import_name]}"
) )
@ -457,16 +463,16 @@ def add_meta(
return page return page
def write_page(path: str, code: str): def write_page(path: str | Path, code: str):
"""Write the given code to the given path. """Write the given code to the given path.
Args: Args:
path: The path to write the code to. path: The path to write the code to.
code: The code to write. code: The code to write.
""" """
path_ops.mkdir(os.path.dirname(path)) path = Path(path)
with open(path, "w", encoding="utf-8") as f: path_ops.mkdir(path.parent)
f.write(code) path.write_text(code, encoding="utf-8")
def empty_dir(path: str | Path, keep_files: list[str] | None = None): def empty_dir(path: str | Path, keep_files: list[str] | None = None):

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -21,42 +21,22 @@ class AppWrap(Fragment):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "AppWrap": ) -> "AppWrap":
"""Create a new AppWrap component. """Create a new AppWrap component.

View File

@ -4,10 +4,11 @@ from __future__ import annotations
from typing import Any, Iterator from typing import Any, Iterator
from reflex.components.component import Component from reflex.components.component import Component, LiteralComponentVar
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.vars import ArrayVar, BooleanVar, ObjectVar, Var from reflex.utils.imports import ParsedImportDict
from reflex.vars import BooleanVar, ObjectVar, Var
class Bare(Component): class Bare(Component):
@ -31,11 +32,79 @@ class Bare(Component):
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) # type: ignore
def _get_all_hooks_internal(self) -> dict[str, None]:
"""Include the hooks for the component.
Returns:
The hooks for the component.
"""
hooks = super()._get_all_hooks_internal()
if isinstance(self.contents, LiteralComponentVar):
hooks |= self.contents._var_value._get_all_hooks_internal()
return hooks
def _get_all_hooks(self) -> dict[str, None]:
"""Include the hooks for the component.
Returns:
The hooks for the component.
"""
hooks = super()._get_all_hooks()
if isinstance(self.contents, LiteralComponentVar):
hooks |= self.contents._var_value._get_all_hooks()
return hooks
def _get_all_imports(self) -> ParsedImportDict:
"""Include the imports for the component.
Returns:
The imports for the component.
"""
imports = super()._get_all_imports()
if isinstance(self.contents, LiteralComponentVar):
var_data = self.contents._get_all_var_data()
if var_data:
imports |= {k: list(v) for k, v in var_data.imports}
return imports
def _get_all_dynamic_imports(self) -> set[str]:
"""Get dynamic imports for the component.
Returns:
The dynamic imports.
"""
dynamic_imports = super()._get_all_dynamic_imports()
if isinstance(self.contents, LiteralComponentVar):
dynamic_imports |= self.contents._var_value._get_all_dynamic_imports()
return dynamic_imports
def _get_all_custom_code(self) -> set[str]:
"""Get custom code for the component.
Returns:
The custom code.
"""
custom_code = super()._get_all_custom_code()
if isinstance(self.contents, LiteralComponentVar):
custom_code |= self.contents._var_value._get_all_custom_code()
return custom_code
def _get_all_refs(self) -> set[str]:
"""Get the refs for the children of the component.
Returns:
The refs for the children.
"""
refs = super()._get_all_refs()
if isinstance(self.contents, LiteralComponentVar):
refs |= self.contents._var_value._get_all_refs()
return refs
def _render(self) -> Tag: def _render(self) -> Tag:
if isinstance(self.contents, Var): if isinstance(self.contents, Var):
if isinstance(self.contents, (BooleanVar, ObjectVar, ArrayVar)): if isinstance(self.contents, (BooleanVar, ObjectVar)):
return Tagless(contents=f"{{{str(self.contents.to_string())}}}") return Tagless(contents=f"{{{self.contents.to_string()!s}}}")
return Tagless(contents=f"{{{str(self.contents)}}}") return Tagless(contents=f"{{{self.contents!s}}}")
return Tagless(contents=str(self.contents)) return Tagless(contents=str(self.contents))
def _get_vars(self, include_children: bool = False) -> Iterator[Var]: def _get_vars(self, include_children: bool = False) -> Iterator[Var]:

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -21,42 +21,22 @@ class Body(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Body": ) -> "Body":
"""Create the component. """Create the component.

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -21,42 +21,22 @@ class NextDocumentLib(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "NextDocumentLib": ) -> "NextDocumentLib":
"""Create the component. """Create the component.
@ -88,42 +68,22 @@ class Html(NextDocumentLib):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Html": ) -> "Html":
"""Create the component. """Create the component.
@ -154,42 +114,22 @@ class DocumentHead(NextDocumentLib):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "DocumentHead": ) -> "DocumentHead":
"""Create the component. """Create the component.
@ -220,42 +160,22 @@ class Main(NextDocumentLib):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Main": ) -> "Main":
"""Create the component. """Create the component.
@ -286,42 +206,22 @@ class NextScript(NextDocumentLib):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "NextScript": ) -> "NextScript":
"""Create the component. """Create the component.

View File

@ -2,16 +2,33 @@
from __future__ import annotations from __future__ import annotations
from typing import List from typing import Dict, Tuple
from reflex.compiler.compiler import _compile_component
from reflex.components.component import Component from reflex.components.component import Component
from reflex.components.el import div, p from reflex.components.datadisplay.logo import svg_logo
from reflex.constants import Hooks, Imports from reflex.components.el import a, button, details, div, h2, hr, p, pre, summary
from reflex.event import EventChain, EventHandler from reflex.event import EventHandler, set_clipboard
from reflex.utils.imports import ImportVar from reflex.state import FrontendEventExceptionState
from reflex.vars.base import Var from reflex.vars.base import Var
from reflex.vars.function import FunctionVar from reflex.vars.function import ArgsFunctionOperation
def on_error_spec(
error: Var[Dict[str, str]], info: Var[Dict[str, str]]
) -> Tuple[Var[str], Var[str]]:
"""The spec for the on_error event handler.
Args:
error: The error message.
info: Additional information about the error.
Returns:
The arguments for the event handler.
"""
return (
error.stack,
info.componentStack,
)
class ErrorBoundary(Component): class ErrorBoundary(Component):
@ -21,59 +38,118 @@ class ErrorBoundary(Component):
tag = "ErrorBoundary" tag = "ErrorBoundary"
# Fired when the boundary catches an error. # Fired when the boundary catches an error.
on_error: EventHandler[lambda error, info: [error, info]] = Var( # type: ignore on_error: EventHandler[on_error_spec]
"logFrontendError"
).to(FunctionVar, EventChain)
# Rendered instead of the children when an error is caught. # Rendered instead of the children when an error is caught.
Fallback_component: Var[Component] = Var(_js_expr="Fallback")._replace( fallback_render: Var[Component]
_var_type=Component
)
def add_imports(self) -> dict[str, list[ImportVar]]: @classmethod
"""Add imports for the component. def create(cls, *children, **props):
"""Create an ErrorBoundary component.
Args:
*children: The children of the component.
**props: The props of the component.
Returns: Returns:
The imports to add. The ErrorBoundary component.
""" """
return Imports.EVENTS if "on_error" not in props:
props["on_error"] = FrontendEventExceptionState.handle_frontend_exception
def add_hooks(self) -> List[str | Var]: if "fallback_render" not in props:
"""Add hooks for the component. props["fallback_render"] = ArgsFunctionOperation.create(
("event_args",),
Returns: Var.create(
The hooks to add. div(
""" div(
return [Hooks.EVENTS, Hooks.FRONTEND_ERRORS] div(
h2(
def add_custom_code(self) -> List[str]: "An error occurred while rendering this page.",
"""Add custom Javascript code into the page that contains this component. font_size="1.25rem",
font_weight="bold",
Custom code is inserted at module level, after any imports. ),
p(
Returns: "This is an error with the application itself.",
The custom code to add. opacity="0.75",
""" ),
fallback_container = div( details(
p("Ooops...Unknown Reflex error has occured:"), summary("Error message", padding="0.5rem"),
p( div(
Var(_js_expr="error.message"), div(
color="red", pre(
), Var(
p("Please contact the support."), _js_expr="event_args.error.stack",
) ),
),
compiled_fallback = _compile_component(fallback_container) padding="0.5rem",
width="fit-content",
return [ ),
f""" width="100%",
function Fallback({{ error, resetErrorBoundary }}) {{ max_height="50vh",
return ( overflow="auto",
{compiled_fallback} background="#000",
); color="#fff",
}} border_radius="0.25rem",
""" ),
] button(
"Copy",
on_click=set_clipboard(
Var(_js_expr="event_args.error.stack"),
),
padding="0.35rem 0.75rem",
margin="0.5rem",
background="#fff",
color="#000",
border="1px solid #000",
border_radius="0.25rem",
font_weight="bold",
),
),
display="flex",
flex_direction="column",
gap="1rem",
max_width="50ch",
border="1px solid #888888",
border_radius="0.25rem",
padding="1rem",
),
hr(
border_color="currentColor",
opacity="0.25",
),
a(
div(
"Built with ",
svg_logo("currentColor"),
display="flex",
align_items="baseline",
justify_content="center",
font_family="monospace",
gap="0.5rem",
),
href="https://reflex.dev",
),
display="flex",
flex_direction="column",
gap="1rem",
),
height="100%",
width="100%",
position="absolute",
display="flex",
align_items="center",
justify_content="center",
)
),
_var_type=Component,
)
else:
props["fallback_render"] = ArgsFunctionOperation.create(
("event_args",),
props["fallback_render"],
_var_type=Component,
)
return super().create(*children, **props)
error_boundary = ErrorBoundary.create error_boundary = ErrorBoundary.create

View File

@ -3,73 +3,60 @@
# ------------------- 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, Callable, Dict, List, Optional, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.utils.imports import ImportVar
from reflex.vars.base import Var from reflex.vars.base import Var
def on_error_spec(
error: Var[Dict[str, str]], info: Var[Dict[str, str]]
) -> Tuple[Var[str], Var[str]]: ...
class ErrorBoundary(Component): class ErrorBoundary(Component):
def add_imports(self) -> dict[str, list[ImportVar]]: ...
def add_hooks(self) -> List[str | Var]: ...
def add_custom_code(self) -> List[str]: ...
@overload @overload
@classmethod @classmethod
def create( # type: ignore def create( # type: ignore
cls, cls,
*children, *children,
Fallback_component: Optional[Union[Component, Var[Component]]] = None, fallback_render: Optional[Union[Component, Var[Component]]] = 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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_error: Optional[
on_double_click: Optional[ Union[
Union[EventHandler, EventSpec, list, Callable, Var] EventType[[], BASE_STATE],
] = None, EventType[[str], BASE_STATE],
on_error: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, EventType[[str, str], BASE_STATE],
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, ]
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None, ] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
**props, **props,
) -> "ErrorBoundary": ) -> "ErrorBoundary":
"""Create the component. """Create an ErrorBoundary component.
Args: Args:
*children: The children of the component. *children: The children of the component.
Fallback_component: Rendered instead of the children when an error is caught. on_error: Fired when the boundary catches an error.
fallback_render: Rendered instead of the children when an error is caught.
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.
id: The id for the component. id: The id for the component.
@ -79,7 +66,7 @@ class ErrorBoundary(Component):
**props: The props of the component. **props: The props of the component.
Returns: Returns:
The component. The ErrorBoundary component.
""" """
... ...

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -21,42 +21,22 @@ class Fragment(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Fragment": ) -> "Fragment":
"""Create the component. """Create the component.

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -21,42 +21,22 @@ class NextHeadLib(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "NextHeadLib": ) -> "NextHeadLib":
"""Create the component. """Create the component.
@ -87,42 +67,22 @@ class Head(NextHeadLib, MemoizationLeaf):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Head": ) -> "Head":
"""Create a new memoization leaf component. """Create a new memoization leaf component.

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -23,42 +23,22 @@ class RawLink(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "RawLink": ) -> "RawLink":
"""Create the component. """Create the component.
@ -98,42 +78,22 @@ class ScriptTag(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "ScriptTag": ) -> "ScriptTag":
"""Create the component. """Create the component.

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -22,42 +22,22 @@ class Title(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Title": ) -> "Title":
"""Create the component. """Create the component.
@ -93,42 +73,22 @@ class Meta(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Meta": ) -> "Meta":
"""Create the component. """Create the component.
@ -169,42 +129,22 @@ class Description(Meta):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Description": ) -> "Description":
"""Create the component. """Create the component.
@ -245,42 +185,22 @@ class Image(Meta):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Image": ) -> "Image":
"""Create the component. """Create the component.

View File

@ -8,7 +8,7 @@ from __future__ import annotations
from typing import Literal from typing import Literal
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import EventHandler from reflex.event import EventHandler, no_args_event_spec
from reflex.vars.base import LiteralVar, Var from reflex.vars.base import LiteralVar, Var
@ -35,13 +35,13 @@ class Script(Component):
) )
# Triggered when the script is loading # Triggered when the script is loading
on_load: EventHandler[lambda: []] on_load: EventHandler[no_args_event_spec]
# Triggered when the script has loaded # Triggered when the script has loaded
on_ready: EventHandler[lambda: []] on_ready: EventHandler[no_args_event_spec]
# Triggered when the script has errored # Triggered when the script has errored
on_error: EventHandler[lambda: []] on_error: EventHandler[no_args_event_spec]
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children, **props) -> Component:

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -28,45 +28,25 @@ class Script(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_error: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_focus: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_load: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mount: Optional[EventType[[], BASE_STATE]] = None,
on_error: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_load: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_ready: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_scroll: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_unmount: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_ready: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Script": ) -> "Script":
"""Create an inline or user-defined script. """Create an inline or user-defined script.
@ -85,6 +65,9 @@ class Script(Component):
*children: The children of the component. *children: The children of the component.
src: Required unless inline script is used src: Required unless inline script is used
strategy: When the script will execute: afterInteractive (defer-like behavior) | beforeInteractive | lazyOnload (async-like behavior) strategy: When the script will execute: afterInteractive (defer-like behavior) | beforeInteractive | lazyOnload (async-like behavior)
on_load: Triggered when the script is loading
on_ready: Triggered when the script has loaded
on_error: Triggered when the script has errored
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.
id: The id for the component. id: The id for the component.

View File

@ -3,6 +3,7 @@
from __future__ import annotations from __future__ import annotations
import copy import copy
import dataclasses
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
@ -16,6 +17,7 @@ from typing import (
Iterator, Iterator,
List, List,
Optional, Optional,
Sequence,
Set, Set,
Type, Type,
Union, Union,
@ -36,13 +38,19 @@ from reflex.constants import (
MemoizationMode, MemoizationMode,
PageNames, PageNames,
) )
from reflex.constants.compiler import SpecialAttributes
from reflex.constants.state import FRONTEND_EVENT_STATE
from reflex.event import ( from reflex.event import (
EventCallback,
EventChain, EventChain,
EventChainVar,
EventHandler, EventHandler,
EventSpec, EventSpec,
EventVar,
call_event_fn, call_event_fn,
call_event_handler, call_event_handler,
get_handler_args, get_handler_args,
no_args_event_spec,
) )
from reflex.style import Style, format_as_emotion from reflex.style import Style, format_as_emotion
from reflex.utils import format, imports, types from reflex.utils import format, imports, types
@ -54,7 +62,15 @@ from reflex.utils.imports import (
parse_imports, parse_imports,
) )
from reflex.vars import VarData from reflex.vars import VarData
from reflex.vars.base import LiteralVar, Var from reflex.vars.base import (
CachedVarOperation,
LiteralVar,
Var,
cached_property_no_lock,
)
from reflex.vars.function import ArgsFunctionOperation, FunctionStringVar
from reflex.vars.number import ternary_operation
from reflex.vars.object import ObjectVar
from reflex.vars.sequence import LiteralArrayVar from reflex.vars.sequence import LiteralArrayVar
@ -142,11 +158,10 @@ class ComponentNamespace(SimpleNamespace):
def __hash__(self) -> int: def __hash__(self) -> int:
"""Get the hash of the namespace. """Get the hash of the namespace.
Returns: Returns:
The hash of the namespace. The hash of the namespace.
""" """
return hash(self.__class__.__name__) return hash(type(self).__name__)
def evaluate_style_namespaces(style: ComponentStyle) -> dict: def evaluate_style_namespaces(style: ComponentStyle) -> dict:
@ -171,6 +186,23 @@ ComponentStyle = Dict[
ComponentChild = Union[types.PrimitiveType, Var, BaseComponent] ComponentChild = Union[types.PrimitiveType, Var, BaseComponent]
def satisfies_type_hint(obj: Any, type_hint: Any) -> bool:
"""Check if an object satisfies a type hint.
Args:
obj: The object to check.
type_hint: The type hint to check against.
Returns:
Whether the object satisfies the type hint.
"""
if isinstance(obj, LiteralVar):
return types._isinstance(obj._var_value, type_hint)
if isinstance(obj, Var):
return types._issubclass(obj._var_type, type_hint)
return types._isinstance(obj, type_hint)
class Component(BaseComponent, ABC): class Component(BaseComponent, ABC):
"""A component with style, event trigger and other props.""" """A component with style, event trigger and other props."""
@ -214,7 +246,7 @@ class Component(BaseComponent, ABC):
_rename_props: Dict[str, str] = {} _rename_props: Dict[str, str] = {}
# custom attribute # custom attribute
custom_attrs: Dict[str, Union[Var, str]] = {} custom_attrs: Dict[str, Union[Var, Any]] = {}
# When to memoize this component and its children. # When to memoize this component and its children.
_memoization_mode: MemoizationMode = MemoizationMode() _memoization_mode: MemoizationMode = MemoizationMode()
@ -445,8 +477,7 @@ class Component(BaseComponent, ABC):
) )
) or ( ) or (
# Else just check if the passed var type is valid. # Else just check if the passed var type is valid.
not passed_types not passed_types and not satisfies_type_hint(value, expected_type)
and not types._issubclass(passed_type, expected_type, value)
): ):
value_name = value._js_expr if isinstance(value, Var) else value value_name = value._js_expr if isinstance(value, Var) else value
@ -466,12 +497,24 @@ class Component(BaseComponent, ABC):
kwargs["event_triggers"][key] = self._create_event_chain( kwargs["event_triggers"][key] = self._create_event_chain(
value=value, # type: ignore value=value, # type: ignore
args_spec=component_specific_triggers[key], args_spec=component_specific_triggers[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] del kwargs[key]
# Place data_ and aria_ attributes into custom_attrs
special_attributes = tuple(
key
for key in kwargs
if key not in fields and SpecialAttributes.is_special(key)
)
if special_attributes:
custom_attrs = kwargs.setdefault("custom_attrs", {})
for key in special_attributes:
custom_attrs[format.to_kebab_case(key)] = kwargs.pop(key)
# Add style props to the component. # Add style props to the component.
style = kwargs.get("style", {}) style = kwargs.get("style", {})
if isinstance(style, List): if isinstance(style, List):
@ -491,8 +534,6 @@ class Component(BaseComponent, ABC):
**{attr: value for attr, value in kwargs.items() if attr not in fields}, **{attr: value for attr, value in kwargs.items() if attr not in fields},
} }
) )
if "custom_attrs" not in kwargs:
kwargs["custom_attrs"] = {}
# Convert class_name to str if it's list # Convert class_name to str if it's list
class_name = kwargs.get("class_name", "") class_name = kwargs.get("class_name", "")
@ -509,20 +550,22 @@ class Component(BaseComponent, ABC):
def _create_event_chain( def _create_event_chain(
self, self,
args_spec: Any, args_spec: types.ArgsSpec | Sequence[types.ArgsSpec],
value: Union[ value: Union[
Var, Var,
EventHandler, EventHandler,
EventSpec, EventSpec,
List[Union[EventHandler, EventSpec]], List[Union[EventHandler, EventSpec, EventVar]],
Callable, Callable,
], ],
key: Optional[str] = None,
) -> Union[EventChain, Var]: ) -> Union[EventChain, Var]:
"""Create an event chain from a variety of input types. """Create an event chain from a variety of input types.
Args: Args:
args_spec: The args_spec of the event trigger being bound. args_spec: The args_spec of the event trigger being bound.
value: The value to create the event chain from. value: The value to create the event chain from.
key: The key of the event trigger being bound.
Returns: Returns:
The event chain. The event chain.
@ -532,11 +575,16 @@ class Component(BaseComponent, ABC):
""" """
# If it's an event chain var, return it. # If it's an event chain var, return it.
if isinstance(value, Var): if isinstance(value, Var):
if value._var_type is not EventChain: if isinstance(value, EventChainVar):
return value
elif isinstance(value, EventVar):
value = [value]
elif issubclass(value._var_type, (EventChain, EventSpec)):
return self._create_event_chain(args_spec, value.guess_type(), key=key)
else:
raise ValueError( raise ValueError(
f"Invalid event chain: {repr(value)} of type {type(value)}" f"Invalid event chain: {value!s} of type {value._var_type}"
) )
return value
elif isinstance(value, EventChain): elif isinstance(value, EventChain):
# Trust that the caller knows what they're doing passing an EventChain directly # Trust that the caller knows what they're doing passing an EventChain directly
return value return value
@ -547,91 +595,92 @@ class Component(BaseComponent, ABC):
# If the input is a list of event handlers, create an event chain. # If the input is a list of event handlers, create an event chain.
if isinstance(value, List): if isinstance(value, List):
events: list[EventSpec] = [] events: List[Union[EventSpec, EventVar]] = []
for v in value: for v in value:
if isinstance(v, (EventHandler, EventSpec)): if isinstance(v, (EventHandler, EventSpec)):
# Call the event handler to get the event. # Call the event handler to get the event.
events.append(call_event_handler(v, args_spec)) events.append(call_event_handler(v, args_spec, key=key))
elif isinstance(v, Callable): elif isinstance(v, Callable):
# Call the lambda to get the event chain. # Call the lambda to get the event chain.
result = call_event_fn(v, args_spec) result = call_event_fn(v, args_spec, key=key)
if isinstance(result, Var): if isinstance(result, Var):
raise ValueError( raise ValueError(
f"Invalid event chain: {v}. Cannot use a Var-returning " f"Invalid event chain: {v}. Cannot use a Var-returning "
"lambda inside an EventChain list." "lambda inside an EventChain list."
) )
events.extend(result) events.extend(result)
elif isinstance(v, EventVar):
events.append(v)
else: else:
raise ValueError(f"Invalid event: {v}") raise ValueError(f"Invalid event: {v}")
# If the input is a callable, create an event chain. # If the input is a callable, create an event chain.
elif isinstance(value, Callable): elif isinstance(value, Callable):
result = call_event_fn(value, args_spec) result = call_event_fn(value, args_spec, key=key)
if isinstance(result, Var): if isinstance(result, Var):
# Recursively call this function if the lambda returned an EventChain Var. # Recursively call this function if the lambda returned an EventChain Var.
return self._create_event_chain(args_spec, result) return self._create_event_chain(args_spec, result, key=key)
events = result events = [*result]
# Otherwise, raise an error. # Otherwise, raise an error.
else: else:
raise ValueError(f"Invalid event chain: {value}") raise ValueError(f"Invalid event chain: {value}")
# Add args to the event specs if necessary. # Add args to the event specs if necessary.
events = [e.with_args(get_handler_args(e)) for e in events] events = [
(e.with_args(get_handler_args(e)) if isinstance(e, EventSpec) else e)
# Collect event_actions from each spec for e in events
event_actions = {} ]
for e in events:
event_actions.update(e.event_actions)
# Return the event chain. # Return the event chain.
if isinstance(args_spec, Var): if isinstance(args_spec, Var):
return EventChain( return EventChain(
events=events, events=events,
args_spec=None, args_spec=None,
event_actions=event_actions, event_actions={},
) )
else: else:
return EventChain( return EventChain(
events=events, events=events,
args_spec=args_spec, args_spec=args_spec,
event_actions=event_actions, event_actions={},
) )
def get_event_triggers(self) -> Dict[str, Any]: def get_event_triggers(
self,
) -> Dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]:
"""Get the event triggers for the component. """Get the event triggers for the component.
Returns: Returns:
The event triggers. The event triggers.
""" """
default_triggers = { default_triggers: Dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]] = {
EventTriggers.ON_FOCUS: lambda: [], EventTriggers.ON_FOCUS: no_args_event_spec,
EventTriggers.ON_BLUR: lambda: [], EventTriggers.ON_BLUR: no_args_event_spec,
EventTriggers.ON_CLICK: lambda: [], EventTriggers.ON_CLICK: no_args_event_spec,
EventTriggers.ON_CONTEXT_MENU: lambda: [], EventTriggers.ON_CONTEXT_MENU: no_args_event_spec,
EventTriggers.ON_DOUBLE_CLICK: lambda: [], EventTriggers.ON_DOUBLE_CLICK: no_args_event_spec,
EventTriggers.ON_MOUSE_DOWN: lambda: [], EventTriggers.ON_MOUSE_DOWN: no_args_event_spec,
EventTriggers.ON_MOUSE_ENTER: lambda: [], EventTriggers.ON_MOUSE_ENTER: no_args_event_spec,
EventTriggers.ON_MOUSE_LEAVE: lambda: [], EventTriggers.ON_MOUSE_LEAVE: no_args_event_spec,
EventTriggers.ON_MOUSE_MOVE: lambda: [], EventTriggers.ON_MOUSE_MOVE: no_args_event_spec,
EventTriggers.ON_MOUSE_OUT: lambda: [], EventTriggers.ON_MOUSE_OUT: no_args_event_spec,
EventTriggers.ON_MOUSE_OVER: lambda: [], EventTriggers.ON_MOUSE_OVER: no_args_event_spec,
EventTriggers.ON_MOUSE_UP: lambda: [], EventTriggers.ON_MOUSE_UP: no_args_event_spec,
EventTriggers.ON_SCROLL: lambda: [], EventTriggers.ON_SCROLL: no_args_event_spec,
EventTriggers.ON_MOUNT: lambda: [], EventTriggers.ON_MOUNT: no_args_event_spec,
EventTriggers.ON_UNMOUNT: lambda: [], EventTriggers.ON_UNMOUNT: no_args_event_spec,
} }
# Look for component specific triggers, # Look for component specific triggers,
# e.g. variable declared as EventHandler types. # e.g. variable declared as EventHandler types.
for field in self.get_fields().values(): for field in self.get_fields().values():
if types._issubclass(field.type_, EventHandler): if types._issubclass(field.outer_type_, EventHandler):
args_spec = None args_spec = None
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 (lambda: []) default_triggers[field.name] = args_spec or (no_args_event_spec) # type: ignore
return default_triggers return default_triggers
def __repr__(self) -> str: def __repr__(self) -> str:
@ -1030,8 +1079,11 @@ class Component(BaseComponent, ABC):
elif isinstance(event, EventChain): elif isinstance(event, EventChain):
event_args = [] event_args = []
for spec in event.events: for spec in event.events:
for args in spec.args: if isinstance(spec, EventSpec):
event_args.extend(args) for args in spec.args:
event_args.extend(args)
else:
event_args.append(spec)
yield event_trigger, event_args yield event_trigger, event_args
def _get_vars(self, include_children: bool = False) -> list[Var]: def _get_vars(self, include_children: bool = False) -> list[Var]:
@ -1058,7 +1110,7 @@ class Component(BaseComponent, ABC):
vars.append(prop_var) vars.append(prop_var)
# Style keeps track of its own VarData instance, so embed in a temp Var that is yielded. # Style keeps track of its own VarData instance, so embed in a temp Var that is yielded.
if isinstance(self.style, dict) and self.style or isinstance(self.style, Var): if (isinstance(self.style, dict) and self.style) or isinstance(self.style, Var):
vars.append( vars.append(
Var( Var(
_js_expr="style", _js_expr="style",
@ -1105,8 +1157,17 @@ class Component(BaseComponent, ABC):
for trigger in self.event_triggers.values(): for trigger in self.event_triggers.values():
if isinstance(trigger, EventChain): if isinstance(trigger, EventChain):
for event in trigger.events: for event in trigger.events:
if event.handler.state_full_name: if isinstance(event, EventCallback):
return True continue
if isinstance(event, EventSpec):
if (
event.handler.state_full_name
and event.handler.state_full_name != FRONTEND_EVENT_STATE
):
return True
else:
if event._var_state:
return True
elif isinstance(trigger, Var) and trigger._var_state: elif isinstance(trigger, Var) and trigger._var_state:
return True return True
return False return False
@ -1280,7 +1341,9 @@ class Component(BaseComponent, ABC):
if self._get_ref_hook(): if self._get_ref_hook():
# Handle hooks needed for attaching react refs to DOM nodes. # Handle hooks needed for attaching react refs to DOM nodes.
_imports.setdefault("react", set()).add(ImportVar(tag="useRef")) _imports.setdefault("react", set()).add(ImportVar(tag="useRef"))
_imports.setdefault(f"/{Dirs.STATE_PATH}", set()).add(ImportVar(tag="refs")) _imports.setdefault(f"$/{Dirs.STATE_PATH}", set()).add(
ImportVar(tag="refs")
)
if self._get_mount_lifecycle_hook(): if self._get_mount_lifecycle_hook():
# Handle hooks for `on_mount` / `on_unmount`. # Handle hooks for `on_mount` / `on_unmount`.
@ -1402,7 +1465,9 @@ class Component(BaseComponent, ABC):
""" """
ref = self.get_ref() ref = self.get_ref()
if ref is not None: if ref is not None:
return f"const {ref} = useRef(null); {str(Var(_js_expr=ref).as_ref())} = {ref};" return (
f"const {ref} = useRef(null); {Var(_js_expr=ref)._as_ref()!s} = {ref};"
)
def _get_vars_hooks(self) -> dict[str, None]: def _get_vars_hooks(self) -> dict[str, None]:
"""Get the hooks required by vars referenced in this component. """Get the hooks required by vars referenced in this component.
@ -1637,7 +1702,7 @@ class CustomComponent(Component):
"""A custom user-defined component.""" """A custom user-defined component."""
# Use the components library. # Use the components library.
library = f"/{Dirs.COMPONENTS_PATH}" library = f"$/{Dirs.COMPONENTS_PATH}"
# The function that creates the component. # The function that creates the component.
component_fn: Callable[..., Component] = Component.create component_fn: Callable[..., Component] = Component.create
@ -1681,8 +1746,9 @@ class CustomComponent(Component):
value = self._create_event_chain( value = self._create_event_chain(
value=value, value=value,
args_spec=event_triggers_in_component_declaration.get( args_spec=event_triggers_in_component_declaration.get(
key, lambda: [] key, no_args_event_spec
), ),
key=key,
) )
self.props[format.to_camel_case(key)] = value self.props[format.to_camel_case(key)] = value
continue continue
@ -1855,6 +1921,11 @@ memo = custom_component
class NoSSRComponent(Component): class NoSSRComponent(Component):
"""A dynamic component that is not rendered on the server.""" """A dynamic component that is not rendered on the server."""
def _get_import_name(self) -> None | str:
if not self.library:
return None
return f"${self.library}" if self.library.startswith("/") else self.library
def _get_imports(self) -> ParsedImportDict: def _get_imports(self) -> ParsedImportDict:
"""Get the imports for the component. """Get the imports for the component.
@ -1868,8 +1939,9 @@ class NoSSRComponent(Component):
_imports = super()._get_imports() _imports = super()._get_imports()
# Do NOT import the main library/tag statically. # Do NOT import the main library/tag statically.
if self.library is not None: import_name = self._get_import_name()
_imports[self.library] = [ if import_name is not None:
_imports[import_name] = [
imports.ImportVar( imports.ImportVar(
tag=None, tag=None,
render=False, render=False,
@ -1887,10 +1959,10 @@ class NoSSRComponent(Component):
opts_fragment = ", { ssr: false });" opts_fragment = ", { ssr: false });"
# extract the correct import name from library name # extract the correct import name from library name
if self.library is None: base_import_name = self._get_import_name()
if base_import_name is None:
raise ValueError("Undefined library for NoSSRComponent") raise ValueError("Undefined library for NoSSRComponent")
import_name = format.format_library_name(base_import_name)
import_name = format.format_library_name(self.library)
library_import = f"const {self.alias if self.alias else self.tag} = dynamic(() => import('{import_name}')" library_import = f"const {self.alias if self.alias else self.tag} = dynamic(() => import('{import_name}')"
mod_import = ( mod_import = (
@ -2205,7 +2277,7 @@ class StatefulComponent(BaseComponent):
""" """
if self.rendered_as_shared: if self.rendered_as_shared:
return { return {
f"/{Dirs.UTILS}/{PageNames.STATEFUL_COMPONENTS}": [ f"$/{Dirs.UTILS}/{PageNames.STATEFUL_COMPONENTS}": [
ImportVar(tag=self.tag) ImportVar(tag=self.tag)
] ]
} }
@ -2315,3 +2387,203 @@ class MemoizationLeaf(Component):
load_dynamic_serializer() load_dynamic_serializer()
class ComponentVar(Var[Component], python_types=BaseComponent):
"""A Var that represents a Component."""
def empty_component() -> Component:
"""Create an empty component.
Returns:
An empty component.
"""
from reflex.components.base.bare import Bare
return Bare.create("")
def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) -> Var:
"""Convert a render dict to a Var.
Args:
tag: The render dict.
imported_names: The names of the imported components.
Returns:
The Var.
"""
if not isinstance(tag, dict):
if isinstance(tag, Component):
return render_dict_to_var(tag.render(), imported_names)
return Var.create(tag)
if "iterable" in tag:
function_return = Var.create(
[
render_dict_to_var(child.render(), imported_names)
for child in tag["children"]
]
)
func = ArgsFunctionOperation.create(
(tag["arg_var_name"], tag["index_var_name"]),
function_return,
)
return FunctionStringVar.create("Array.prototype.map.call").call(
tag["iterable"]
if not isinstance(tag["iterable"], ObjectVar)
else tag["iterable"].items(),
func,
)
if tag["name"] == "match":
element = tag["cond"]
conditionals = tag["default"]
for case in tag["match_cases"][::-1]:
condition = case[0].to_string() == element.to_string()
for pattern in case[1:-1]:
condition = condition | (pattern.to_string() == element.to_string())
conditionals = ternary_operation(
condition,
case[-1],
conditionals,
)
return conditionals
if "cond" in tag:
return ternary_operation(
tag["cond"],
render_dict_to_var(tag["true_value"], imported_names),
render_dict_to_var(tag["false_value"], imported_names)
if tag["false_value"] is not None
else Var.create(None),
)
props = {}
special_props = []
for prop_str in tag["props"]:
if "=" not in prop_str:
special_props.append(Var(prop_str).to(ObjectVar))
continue
prop = prop_str.index("=")
key = prop_str[:prop]
value = prop_str[prop + 2 : -1]
props[key] = value
props = Var.create({Var.create(k): Var(v) for k, v in props.items()})
for prop in special_props:
props = props.merge(prop)
contents = tag["contents"][1:-1] if tag["contents"] else None
raw_tag_name = tag.get("name")
tag_name = Var(raw_tag_name or "Fragment")
tag_name = (
Var.create(raw_tag_name)
if raw_tag_name
and raw_tag_name.split(".")[0] not in imported_names
and raw_tag_name.lower() == raw_tag_name
else tag_name
)
return FunctionStringVar.create(
"jsx",
).call(
tag_name,
props,
*([Var(contents)] if contents is not None else []),
*[render_dict_to_var(child, imported_names) for child in tag["children"]],
)
@dataclasses.dataclass(
eq=False,
frozen=True,
)
class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
"""A Var that represents a Component."""
_var_value: BaseComponent = dataclasses.field(default_factory=empty_component)
@cached_property_no_lock
def _cached_var_name(self) -> str:
"""Get the name of the var.
Returns:
The name of the var.
"""
var_data = self._get_all_var_data()
if var_data is not None:
# flatten imports
imported_names = {j.alias or j.name for i in var_data.imports for j in i[1]}
else:
imported_names = set()
return str(render_dict_to_var(self._var_value.render(), imported_names))
@cached_property_no_lock
def _cached_get_all_var_data(self) -> VarData | None:
"""Get the VarData for the var.
Returns:
The VarData for the var.
"""
return VarData.merge(
VarData(
imports={
"@emotion/react": [
ImportVar(tag="jsx"),
],
}
),
VarData(
imports=self._var_value._get_all_imports(),
),
VarData(
imports={
"react": [
ImportVar(tag="Fragment"),
],
}
),
)
def __hash__(self) -> int:
"""Get the hash of the var.
Returns:
The hash of the var.
"""
return hash((type(self).__name__, self._js_expr))
@classmethod
def create(
cls,
value: Component,
_var_data: VarData | None = None,
):
"""Create a var from a value.
Args:
value: The value of the var.
_var_data: Additional hooks and imports associated with the Var.
Returns:
The var.
"""
return LiteralComponentVar(
_js_expr="",
_var_type=type(value),
_var_data=_var_data,
_var_value=value,
)

View File

@ -66,8 +66,8 @@ class WebsocketTargetURL(Var):
_js_expr="getBackendURL(env.EVENT).href", _js_expr="getBackendURL(env.EVENT).href",
_var_data=VarData( _var_data=VarData(
imports={ imports={
"/env.json": [ImportVar(tag="env", is_default=True)], "$/env.json": [ImportVar(tag="env", is_default=True)],
f"/{Dirs.STATE_PATH}": [ImportVar(tag="getBackendURL")], f"$/{Dirs.STATE_PATH}": [ImportVar(tag="getBackendURL")],
}, },
), ),
_var_type=WebsocketTargetURL, _var_type=WebsocketTargetURL,
@ -109,8 +109,8 @@ class ConnectionToaster(Toaster):
) )
individual_hooks = [ individual_hooks = [
f"const toast_props = {str(LiteralVar.create(props))};", f"const toast_props = {LiteralVar.create(props)!s};",
f"const [userDismissed, setUserDismissed] = useState(false);", "const [userDismissed, setUserDismissed] = useState(false);",
FunctionStringVar( FunctionStringVar(
"useEffect", "useEffect",
_var_data=VarData( _var_data=VarData(
@ -124,7 +124,7 @@ class ConnectionToaster(Toaster):
Var( Var(
_js_expr=f""" _js_expr=f"""
() => {{ () => {{
if ({str(has_too_many_connection_errors)}) {{ if ({has_too_many_connection_errors!s}) {{
if (!userDismissed) {{ if (!userDismissed) {{
toast.error( toast.error(
`Cannot connect to server: ${{{connection_error}}}.`, `Cannot connect to server: ${{{connection_error}}}.`,

View File

@ -3,14 +3,14 @@
# ------------------- 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, Callable, 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.components.el.elements.typography import Div 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 EventHandler, EventSpec from reflex.event import BASE_STATE, 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
@ -88,42 +88,22 @@ class ConnectionToaster(Toaster):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "ConnectionToaster": ) -> "ConnectionToaster":
"""Create a connection toaster component. """Create a connection toaster component.
@ -168,42 +148,22 @@ class ConnectionBanner(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "ConnectionBanner": ) -> "ConnectionBanner":
"""Create a connection banner component. """Create a connection banner component.
@ -227,42 +187,22 @@ class ConnectionModal(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "ConnectionModal": ) -> "ConnectionModal":
"""Create a connection banner component. """Create a connection banner component.
@ -287,42 +227,22 @@ class WifiOffPulse(Icon):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = 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.
@ -380,48 +300,28 @@ class ConnectionPulser(Div):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "ConnectionPulser": ) -> "ConnectionPulser":
"""Create a connection pulser component. """Create a connection pulser component.
Args: Args:
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.

View File

@ -21,10 +21,10 @@ route_not_found: Var = Var(_js_expr=constants.ROUTE_NOT_FOUND)
class ClientSideRouting(Component): class ClientSideRouting(Component):
"""The client-side routing component.""" """The client-side routing component."""
library = "/utils/client_side_routing" library = "$/utils/client_side_routing"
tag = "useClientSideRouting" tag = "useClientSideRouting"
def add_hooks(self) -> list[str]: def add_hooks(self) -> list[str | Var]:
"""Get the hooks to render. """Get the hooks to render.
Returns: Returns:
@ -66,4 +66,4 @@ class Default404Page(Component):
tag = "Error" tag = "Error"
is_default = True is_default = True
status_code: Var[int] = 404 # type: ignore status_code: Var[int] = Var.create(404)

View File

@ -3,17 +3,17 @@
# ------------------- 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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
route_not_found: Var route_not_found: Var
class ClientSideRouting(Component): class ClientSideRouting(Component):
def add_hooks(self) -> list[str]: ... def add_hooks(self) -> list[str | Var]: ...
def render(self) -> str: ... def render(self) -> str: ...
@overload @overload
@classmethod @classmethod
@ -25,42 +25,22 @@ class ClientSideRouting(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "ClientSideRouting": ) -> "ClientSideRouting":
"""Create the component. """Create the component.
@ -94,42 +74,22 @@ class Default404Page(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Default404Page": ) -> "Default404Page":
"""Create the component. """Create the component.

View File

@ -2,11 +2,11 @@
from __future__ import annotations from __future__ import annotations
from typing import Dict, List, Union from typing import Dict, List, Tuple, Union
from reflex.components.base.fragment import Fragment from reflex.components.base.fragment import Fragment
from reflex.components.tags.tag import Tag from reflex.components.tags.tag import Tag
from reflex.event import EventChain, EventHandler from reflex.event import EventChain, EventHandler, passthrough_event_spec
from reflex.utils.format import format_prop, wrap from reflex.utils.format import format_prop, wrap
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
from reflex.vars import get_unique_variable_name from reflex.vars import get_unique_variable_name
@ -20,7 +20,7 @@ class Clipboard(Fragment):
targets: Var[List[str]] targets: Var[List[str]]
# Called when the user pastes data into the document. Data is a list of tuples of (mime_type, data). Binary types will be base64 encoded as a data uri. # Called when the user pastes data into the document. Data is a list of tuples of (mime_type, data). Binary types will be base64 encoded as a data uri.
on_paste: EventHandler[lambda data: [data]] on_paste: EventHandler[passthrough_event_spec(List[Tuple[str, str]])]
# Save the original event actions for the on_paste event. # Save the original event actions for the on_paste event.
on_paste_event_actions: Var[Dict[str, Union[bool, int]]] on_paste_event_actions: Var[Dict[str, Union[bool, int]]]
@ -51,7 +51,7 @@ class Clipboard(Fragment):
return super().create(*children, **props) return super().create(*children, **props)
def _exclude_props(self) -> list[str]: def _exclude_props(self) -> list[str]:
return super()._exclude_props() + ["on_paste", "on_paste_event_actions"] return [*super()._exclude_props(), "on_paste", "on_paste_event_actions"]
def _render(self) -> Tag: def _render(self) -> Tag:
tag = super()._render() tag = super()._render()
@ -67,7 +67,7 @@ class Clipboard(Fragment):
The import dict for the component. The import dict for the component.
""" """
return { return {
"/utils/helpers/paste.js": ImportVar( "$/utils/helpers/paste.js": ImportVar(
tag="usePasteHandler", is_default=True tag="usePasteHandler", is_default=True
), ),
} }

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, 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
@ -26,43 +26,28 @@ class Clipboard(Fragment):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_paste: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[
] = None, EventType[[], BASE_STATE],
on_mouse_leave: Optional[ EventType[[list[tuple[str, str]]], BASE_STATE],
Union[EventHandler, EventSpec, list, Callable, Var] ]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_paste: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None, ] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
**props, **props,
) -> "Clipboard": ) -> "Clipboard":
"""Create a Clipboard component. """Create a Clipboard component.
@ -70,6 +55,7 @@ class Clipboard(Fragment):
Args: Args:
*children: The children of the component. *children: The children of the component.
targets: The element ids to attach the event listener to. Defaults to all child components or the document. targets: The element ids to attach the event listener to. Defaults to all child components or the document.
on_paste: Called when the user pastes data into the document. Data is a list of tuples of (mime_type, data). Binary types will be base64 encoded as a data uri.
on_paste_event_actions: Save the original event actions for the on_paste event. on_paste_event_actions: Save the original event actions for the on_paste event.
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.

View File

@ -15,7 +15,7 @@ from reflex.vars.base import LiteralVar, Var
from reflex.vars.number import ternary_operation from reflex.vars.number import ternary_operation
_IS_TRUE_IMPORT: ImportDict = { _IS_TRUE_IMPORT: ImportDict = {
f"/{Dirs.STATE_PATH}": [ImportVar(tag="isTrue")], f"$/{Dirs.STATE_PATH}": [ImportVar(tag="isTrue")],
} }
@ -49,9 +49,9 @@ class Cond(MemoizationLeaf):
The conditional component. The conditional component.
""" """
# Wrap everything in fragments. # Wrap everything in fragments.
if comp1.__class__.__name__ != "Fragment": if type(comp1).__name__ != "Fragment":
comp1 = Fragment.create(comp1) comp1 = Fragment.create(comp1)
if comp2 is None or comp2.__class__.__name__ != "Fragment": if comp2 is None or type(comp2).__name__ != "Fragment":
comp2 = Fragment.create(comp2) if comp2 else Fragment.create() comp2 = Fragment.create(comp2) if comp2 else Fragment.create()
return Fragment.create( return Fragment.create(
cls( cls(
@ -94,7 +94,7 @@ class Cond(MemoizationLeaf):
).set( ).set(
props=tag.format_props(), props=tag.format_props(),
), ),
cond_state=f"isTrue({str(self.cond)})", cond_state=f"isTrue({self.cond!s})",
) )
def add_imports(self) -> ImportDict: def add_imports(self) -> ImportDict:
@ -171,6 +171,14 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
) )
@overload
def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... # type: ignore
@overload
def color_mode_cond(light: Any, dark: Any = None) -> Var: ...
def color_mode_cond(light: Any, dark: Any = None) -> Var | Component: def color_mode_cond(light: Any, dark: Any = None) -> Var | Component:
"""Create a component or Prop based on color_mode. """Create a component or Prop based on color_mode.

View File

@ -6,7 +6,7 @@ from typing import Any, Type, Union
from reflex.components.component import Component from reflex.components.component import Component
from reflex.constants import EventTriggers from reflex.constants import EventTriggers
from reflex.event import EventHandler from reflex.event import EventHandler, no_args_event_spec
from reflex.vars import VarData from reflex.vars import VarData
from reflex.vars.base import Var from reflex.vars.base import Var
@ -46,7 +46,7 @@ class DebounceInput(Component):
element: Var[Type[Component]] element: Var[Type[Component]]
# Fired when the input value changes # Fired when the input value changes
on_change: EventHandler[lambda e0: [e0.value]] on_change: EventHandler[no_args_event_spec]
@classmethod @classmethod
def create(cls, *children: Component, **props: Any) -> Component: def create(cls, *children: Component, **props: Any) -> Component:
@ -118,7 +118,7 @@ class DebounceInput(Component):
_var_type=Type[Component], _var_type=Type[Component],
_var_data=VarData( _var_data=VarData(
imports=child._get_imports(), imports=child._get_imports(),
hooks=child._get_hooks_internal(), hooks=child._get_all_hooks(),
), ),
), ),
) )
@ -128,6 +128,10 @@ class DebounceInput(Component):
component.event_triggers.update(child.event_triggers) component.event_triggers.update(child.event_triggers)
component.children = child.children component.children = child.children
component._rename_props = child._rename_props component._rename_props = child._rename_props
outer_get_all_custom_code = component._get_all_custom_code
component._get_all_custom_code = lambda: outer_get_all_custom_code().union(
child._get_all_custom_code()
)
return component return component
def _render(self): def _render(self):

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -30,43 +30,23 @@ class DebounceInput(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_change: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_change: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "DebounceInput": ) -> "DebounceInput":
"""Create a DebounceInput component. """Create a DebounceInput component.

View File

@ -54,7 +54,7 @@ class Foreach(Component):
iterable = LiteralVar.create(iterable) iterable = LiteralVar.create(iterable)
if iterable._var_type == Any: if iterable._var_type == Any:
raise ForeachVarError( raise ForeachVarError(
f"Could not foreach over var `{str(iterable)}` of type Any. " f"Could not foreach over var `{iterable!s}` of type Any. "
"(If you are trying to foreach over a state var, add a type annotation to the var). " "(If you are trying to foreach over a state var, add a type annotation to the var). "
"See https://reflex.dev/docs/library/dynamic-rendering/foreach/" "See https://reflex.dev/docs/library/dynamic-rendering/foreach/"
) )

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, Callable, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.el.elements.typography import Div from reflex.components.el.elements.typography import Div
from reflex.event import EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -48,42 +48,22 @@ class Html(Div):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Html": ) -> "Html":
"""Create a html component. """Create a html component.
@ -91,7 +71,7 @@ class Html(Div):
Args: Args:
*children: The children of the component. *children: The children of the component.
dangerouslySetInnerHTML: The HTML to render. dangerouslySetInnerHTML: The HTML to render.
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.

View File

@ -2,26 +2,34 @@
from __future__ import annotations from __future__ import annotations
import os
from pathlib import Path from pathlib import Path
from typing import Callable, ClassVar, Dict, List, Optional from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf from reflex.components.base.fragment import Fragment
from reflex.components.component import (
Component,
ComponentNamespace,
MemoizationLeaf,
StatefulComponent,
)
from reflex.components.el.elements.forms import Input from reflex.components.el.elements.forms import Input
from reflex.components.radix.themes.layout.box import Box from reflex.components.radix.themes.layout.box import Box
from reflex.config import environment
from reflex.constants import Dirs from reflex.constants import Dirs
from reflex.constants.compiler import Hooks, Imports
from reflex.event import ( from reflex.event import (
CallableEventSpec, CallableEventSpec,
EventChain, EventChain,
EventHandler, EventHandler,
EventSpec, EventSpec,
call_event_fn, call_event_fn,
call_script,
parse_args_spec, parse_args_spec,
run_script,
) )
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, LiteralVar, Var from reflex.vars.base import CallableVar, 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"
@ -29,7 +37,7 @@ DEFAULT_UPLOAD_ID: str = "default"
upload_files_context_var_data: VarData = VarData( upload_files_context_var_data: VarData = VarData(
imports={ imports={
"react": "useContext", "react": "useContext",
f"/{Dirs.CONTEXTS_PATH}": "UploadFilesContext", f"$/{Dirs.CONTEXTS_PATH}": "UploadFilesContext",
}, },
hooks={ hooks={
"const [filesById, setFilesById] = useContext(UploadFilesContext);": None, "const [filesById, setFilesById] = useContext(UploadFilesContext);": None,
@ -53,7 +61,7 @@ def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> Var:
id_var = LiteralStringVar.create(id_) id_var = LiteralStringVar.create(id_)
var_name = f"""e => setFilesById(filesById => {{ var_name = f"""e => setFilesById(filesById => {{
const updatedFilesById = Object.assign({{}}, filesById); const updatedFilesById = Object.assign({{}}, filesById);
updatedFilesById[{str(id_var)}] = e; updatedFilesById[{id_var!s}] = e;
return updatedFilesById; return updatedFilesById;
}}) }})
""" """
@ -79,7 +87,7 @@ def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> Var:
""" """
id_var = LiteralStringVar.create(id_) id_var = LiteralStringVar.create(id_)
return Var( return Var(
_js_expr=f"(filesById[{str(id_var)}] ? filesById[{str(id_var)}].map((f) => (f.path || f.name)) : [])", _js_expr=f"(filesById[{id_var!s}] ? filesById[{id_var!s}].map((f) => (f.path || f.name)) : [])",
_var_type=List[str], _var_type=List[str],
_var_data=VarData.merge( _var_data=VarData.merge(
upload_files_context_var_data, id_var._get_all_var_data() upload_files_context_var_data, id_var._get_all_var_data()
@ -99,8 +107,9 @@ def clear_selected_files(id_: str = DEFAULT_UPLOAD_ID) -> EventSpec:
""" """
# UploadFilesProvider assigns a special function to clear selected files # UploadFilesProvider assigns a special function to clear selected files
# into the shared global refs object to make it accessible outside a React # into the shared global refs object to make it accessible outside a React
# component via `call_script` (otherwise backend could never clear files). # component via `run_script` (otherwise backend could never clear files).
return call_script(f"refs['__clear_selected_files']({id_!r})") func = Var("__clear_selected_files")._as_ref()
return run_script(f"{func}({id_!r})")
def cancel_upload(upload_id: str) -> EventSpec: def cancel_upload(upload_id: str) -> EventSpec:
@ -112,9 +121,8 @@ def cancel_upload(upload_id: str) -> EventSpec:
Returns: Returns:
An event spec that cancels the upload when triggered. An event spec that cancels the upload when triggered.
""" """
return call_script( controller = Var(f"__upload_controllers_{upload_id}")._as_ref()
f"upload_controllers[{str(LiteralVar.create(upload_id))}]?.abort()" return run_script(f"{controller}?.abort()")
)
def get_upload_dir() -> Path: def get_upload_dir() -> Path:
@ -125,9 +133,7 @@ def get_upload_dir() -> Path:
""" """
Upload.is_used = True Upload.is_used = True
uploaded_files_dir = Path( uploaded_files_dir = environment.REFLEX_UPLOADED_FILES_DIR.get()
os.environ.get("REFLEX_UPLOADED_FILES_DIR", "./uploaded_files")
)
uploaded_files_dir.mkdir(parents=True, exist_ok=True) uploaded_files_dir.mkdir(parents=True, exist_ok=True)
return uploaded_files_dir return uploaded_files_dir
@ -136,8 +142,8 @@ uploaded_files_url_prefix = Var(
_js_expr="getBackendURL(env.UPLOAD)", _js_expr="getBackendURL(env.UPLOAD)",
_var_data=VarData( _var_data=VarData(
imports={ imports={
f"/{Dirs.STATE_PATH}": "getBackendURL", f"$/{Dirs.STATE_PATH}": "getBackendURL",
"/env.json": ImportVar(tag="env", is_default=True), "$/env.json": ImportVar(tag="env", is_default=True),
} }
), ),
).to(str) ).to(str)
@ -157,7 +163,7 @@ def get_upload_url(file_path: str) -> Var[str]:
return uploaded_files_url_prefix + "/" + file_path return uploaded_files_url_prefix + "/" + file_path
def _on_drop_spec(files: Var): def _on_drop_spec(files: Var) -> Tuple[Var[Any]]:
"""Args spec for the on_drop event trigger. """Args spec for the on_drop event trigger.
Args: Args:
@ -166,24 +172,29 @@ def _on_drop_spec(files: Var):
Returns: Returns:
Signature for on_drop handler including the files to upload. Signature for on_drop handler including the files to upload.
""" """
return [files] return (files,)
class UploadFilesProvider(Component): class UploadFilesProvider(Component):
"""AppWrap component that provides a dict of selected files by ID via useContext.""" """AppWrap component that provides a dict of selected files by ID via useContext."""
library = f"/{Dirs.CONTEXTS_PATH}" library = f"$/{Dirs.CONTEXTS_PATH}"
tag = "UploadFilesProvider" tag = "UploadFilesProvider"
class GhostUpload(Fragment):
"""A ghost upload component."""
# Fired when files are dropped.
on_drop: EventHandler[_on_drop_spec]
class Upload(MemoizationLeaf): class Upload(MemoizationLeaf):
"""A file upload component.""" """A file upload component."""
library = "react-dropzone@14.2.3" library = "react-dropzone@14.2.10"
tag = "ReactDropzone" tag = ""
is_default = True
# The list of accepted file types. This should be a dictionary of MIME types as keys and array of file formats as # The list of accepted file types. This should be a dictionary of MIME types as keys and array of file formats as
# values. # values.
@ -203,7 +214,7 @@ class Upload(MemoizationLeaf):
min_size: Var[int] min_size: Var[int]
# Whether to allow multiple files to be uploaded. # Whether to allow multiple files to be uploaded.
multiple: Var[bool] = True # type: ignore multiple: Var[bool]
# Whether to disable click to upload. # Whether to disable click to upload.
no_click: Var[bool] no_click: Var[bool]
@ -234,6 +245,8 @@ class Upload(MemoizationLeaf):
# Mark the Upload component as used in the app. # Mark the Upload component as used in the app.
cls.is_used = True cls.is_used = True
props.setdefault("multiple", True)
# Apply the default classname # Apply the default classname
given_class_name = props.pop("class_name", []) given_class_name = props.pop("class_name", [])
if isinstance(given_class_name, str): if isinstance(given_class_name, str):
@ -245,17 +258,6 @@ class Upload(MemoizationLeaf):
upload_props = { upload_props = {
key: value for key, value in props.items() if key in supported_props key: value for key, value in props.items() if key in supported_props
} }
# The file input to use.
upload = Input.create(type="file")
upload.special_props = [Var(_js_expr="{...getInputProps()}", _var_type=None)]
# The dropzone to use.
zone = Box.create(
upload,
*children,
**{k: v for k, v in props.items() if k not in supported_props},
)
zone.special_props = [Var(_js_expr="{...getRootProps()}", _var_type=None)]
# Create the component. # Create the component.
upload_props["id"] = props.get("id", DEFAULT_UPLOAD_ID) upload_props["id"] = props.get("id", DEFAULT_UPLOAD_ID)
@ -277,9 +279,75 @@ class Upload(MemoizationLeaf):
), ),
) )
upload_props["on_drop"] = on_drop upload_props["on_drop"] = on_drop
input_props_unique_name = get_unique_variable_name()
root_props_unique_name = get_unique_variable_name()
event_var, callback_str = StatefulComponent._get_memoized_event_triggers(
GhostUpload.create(on_drop=upload_props["on_drop"])
)["on_drop"]
upload_props["on_drop"] = event_var
upload_props = {
format.to_camel_case(key): value for key, value in upload_props.items()
}
use_dropzone_arguments = Var.create(
{
"onDrop": event_var,
**upload_props,
}
)
left_side = f"const {{getRootProps: {root_props_unique_name}, getInputProps: {input_props_unique_name}}} "
right_side = f"useDropzone({use_dropzone_arguments!s})"
var_data = VarData.merge(
VarData(
imports=Imports.EVENTS,
hooks={Hooks.EVENTS: None},
),
event_var._get_all_var_data(),
use_dropzone_arguments._get_all_var_data(),
VarData(
hooks={
callback_str: None,
f"{left_side} = {right_side};": None,
},
imports={
"react-dropzone": "useDropzone",
**Imports.EVENTS,
},
),
)
# The file input to use.
upload = Input.create(type="file")
upload.special_props = [
Var(
_js_expr=f"{{...{input_props_unique_name}()}}",
_var_type=None,
_var_data=var_data,
)
]
# The dropzone to use.
zone = Box.create(
upload,
*children,
**{k: v for k, v in props.items() if k not in supported_props},
)
zone.special_props = [
Var(
_js_expr=f"{{...{root_props_unique_name}()}}",
_var_type=None,
_var_data=var_data,
)
]
return super().create( return super().create(
zone, zone,
**upload_props,
) )
@classmethod @classmethod
@ -297,11 +365,6 @@ class Upload(MemoizationLeaf):
return (arg_value[0], placeholder) return (arg_value[0], placeholder)
return arg_value return arg_value
def _render(self):
out = super()._render()
out.args = ("getRootProps", "getInputProps")
return out
@staticmethod @staticmethod
def _get_app_wrap_components() -> dict[tuple[int, str], Component]: def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
return { return {

View File

@ -4,15 +4,12 @@
# This file was generated by `reflex/utils/pyi_generator.py`! # This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------ # ------------------------------------------------------
from pathlib import Path from pathlib import Path
from typing import Any, Callable, ClassVar, Dict, List, Optional, Union, overload from typing import Any, ClassVar, Dict, List, Optional, Union, overload
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 ( from reflex.event import BASE_STATE, CallableEventSpec, EventSpec, EventType
CallableEventSpec,
EventHandler,
EventSpec,
)
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
@ -34,8 +31,8 @@ uploaded_files_url_prefix = Var(
_js_expr="getBackendURL(env.UPLOAD)", _js_expr="getBackendURL(env.UPLOAD)",
_var_data=VarData( _var_data=VarData(
imports={ imports={
f"/{Dirs.STATE_PATH}": "getBackendURL", f"$/{Dirs.STATE_PATH}": "getBackendURL",
"/env.json": ImportVar(tag="env", is_default=True), "$/env.json": ImportVar(tag="env", is_default=True),
} }
), ),
).to(str) ).to(str)
@ -53,42 +50,22 @@ class UploadFilesProvider(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "UploadFilesProvider": ) -> "UploadFilesProvider":
"""Create the component. """Create the component.
@ -108,6 +85,56 @@ class UploadFilesProvider(Component):
""" """
... ...
class GhostUpload(Fragment):
@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[[], BASE_STATE]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None,
on_drop: Optional[
Union[EventType[[], BASE_STATE], EventType[[Any], BASE_STATE]]
] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
**props,
) -> "GhostUpload":
"""Create the component.
Args:
*children: The children of the component.
on_drop: Fired when files are dropped.
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.
"""
...
class Upload(MemoizationLeaf): class Upload(MemoizationLeaf):
is_used: ClassVar[bool] = False is_used: ClassVar[bool] = False
@ -130,43 +157,25 @@ class Upload(MemoizationLeaf):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_drop: Optional[
on_double_click: Optional[ Union[EventType[[], BASE_STATE], EventType[[Any], BASE_STATE]]
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_drop: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None, ] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = 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.
@ -182,6 +191,7 @@ class Upload(MemoizationLeaf):
no_click: Whether to disable click to upload. no_click: Whether to disable click to upload.
no_drag: Whether to disable drag and drop. no_drag: Whether to disable drag and drop.
no_keyboard: Whether to disable using the space/enter keys to upload. no_keyboard: Whether to disable using the space/enter keys to upload.
on_drop: Fired when files are dropped.
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.
id: The id for the component. id: The id for the component.
@ -215,43 +225,25 @@ class StyledUpload(Upload):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_drop: Optional[
on_double_click: Optional[ Union[EventType[[], BASE_STATE], EventType[[Any], BASE_STATE]]
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_drop: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None, ] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = 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.
@ -267,6 +259,7 @@ class StyledUpload(Upload):
no_click: Whether to disable click to upload. no_click: Whether to disable click to upload.
no_drag: Whether to disable drag and drop. no_drag: Whether to disable drag and drop.
no_keyboard: Whether to disable using the space/enter keys to upload. no_keyboard: Whether to disable using the space/enter keys to upload.
on_drop: Fired when files are dropped.
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.
id: The id for the component. id: The id for the component.
@ -300,43 +293,25 @@ class UploadNamespace(ComponentNamespace):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_drop: Optional[
on_double_click: Optional[ Union[EventType[[], BASE_STATE], EventType[[Any], BASE_STATE]]
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_drop: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None, ] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = 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.
@ -352,6 +327,7 @@ class UploadNamespace(ComponentNamespace):
no_click: Whether to disable click to upload. no_click: Whether to disable click to upload.
no_drag: Whether to disable drag and drop. no_drag: Whether to disable drag and drop.
no_keyboard: Whether to disable using the space/enter keys to upload. no_keyboard: Whether to disable using the space/enter keys to upload.
on_drop: Fired when files are dropped.
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.
id: The id for the component. id: The id for the component.

View File

@ -8,13 +8,14 @@ from typing import ClassVar, Dict, Literal, Optional, Union
from reflex.components.component import Component, ComponentNamespace from reflex.components.component import Component, ComponentNamespace
from reflex.components.core.cond import color_mode_cond from reflex.components.core.cond import color_mode_cond
from reflex.components.lucide.icon import Icon from reflex.components.lucide.icon import Icon
from reflex.components.markdown.markdown import _LANGUAGE, MarkdownComponentMap
from reflex.components.radix.themes.components.button import Button from reflex.components.radix.themes.components.button import Button
from reflex.components.radix.themes.layout.box import Box 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 console, format
from reflex.utils.imports import ImportDict, ImportVar from reflex.utils.imports import ImportVar
from reflex.vars.base import LiteralVar, Var, VarData from reflex.vars.base import LiteralVar, Var, VarData
LiteralCodeLanguage = Literal[ LiteralCodeLanguage = Literal[
@ -378,10 +379,10 @@ for theme_name in dir(Theme):
setattr(Theme, theme_name, getattr(Theme, theme_name)._replace(_var_type=Theme)) setattr(Theme, theme_name, getattr(Theme, theme_name)._replace(_var_type=Theme))
class CodeBlock(Component): class CodeBlock(Component, MarkdownComponentMap):
"""A code block.""" """A code block."""
library = "react-syntax-highlighter@15.5.0" library = "react-syntax-highlighter@15.6.0"
tag = "PrismAsyncLight" tag = "PrismAsyncLight"
@ -391,7 +392,7 @@ class CodeBlock(Component):
theme: Var[Union[Theme, str]] = Theme.one_light theme: Var[Union[Theme, str]] = Theme.one_light
# The language to use. # The language to use.
language: Var[LiteralCodeLanguage] = "python" # type: ignore language: Var[LiteralCodeLanguage] = Var.create("python")
# The code to display. # The code to display.
code: Var[str] code: Var[str]
@ -411,53 +412,22 @@ class CodeBlock(Component):
# Props passed down to the code tag. # Props passed down to the code tag.
code_tag_props: Var[Dict[str, str]] code_tag_props: Var[Dict[str, str]]
def add_imports(self) -> ImportDict: # Whether a copy button should appear.
"""Add imports for the CodeBlock component. can_copy: Optional[bool] = False
Returns: # A custom copy button to override the default one.
The import dict. copy_button: Optional[Union[bool, Component]] = None
"""
imports_: ImportDict = {}
if (
self.language is not None
and (language_without_quotes := str(self.language).replace('"', ""))
in LiteralCodeLanguage.__args__ # type: ignore
):
imports_[
f"react-syntax-highlighter/dist/cjs/languages/prism/{language_without_quotes}"
] = [
ImportVar(
tag=format.to_camel_case(language_without_quotes),
is_default=True,
install=False,
)
]
return imports_
def _get_custom_code(self) -> Optional[str]:
if (
self.language is not None
and (language_without_quotes := str(self.language).replace('"', ""))
in LiteralCodeLanguage.__args__ # type: ignore
):
return f"{self.alias}.registerLanguage('{language_without_quotes}', {format.to_camel_case(language_without_quotes)})"
@classmethod @classmethod
def create( def create(
cls, cls,
*children, *children,
can_copy: Optional[bool] = False,
copy_button: Optional[Union[bool, Component]] = None,
**props, **props,
): ):
"""Create a text component. """Create a text component.
Args: Args:
*children: The children of the component. *children: The children of the component.
can_copy: Whether a copy button should appears.
copy_button: A custom copy button to override the default one.
**props: The props to pass to the component. **props: The props to pass to the component.
Returns: Returns:
@ -465,6 +435,8 @@ class CodeBlock(Component):
""" """
# This component handles style in a special prop. # This component handles style in a special prop.
custom_style = props.pop("custom_style", {}) custom_style = props.pop("custom_style", {})
can_copy = props.pop("can_copy", False)
copy_button = props.pop("copy_button", None)
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.
@ -530,12 +502,55 @@ class CodeBlock(Component):
theme = self.theme theme = self.theme
out.add_props(style=theme).remove_props("theme", "code").add_props( out.add_props(style=theme).remove_props("theme", "code", "language").add_props(
children=self.code children=self.code, language=_LANGUAGE
) )
return out return out
def _exclude_props(self) -> list[str]:
return ["can_copy", "copy_button"]
@classmethod
def _get_language_registration_hook(cls) -> str:
"""Get the hook to register the language.
Returns:
The hook to register the language.
"""
return f"""
if ({_LANGUAGE!s}) {{
(async () => {{
try {{
const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${{{_LANGUAGE!s}}}`);
SyntaxHighlighter.registerLanguage({_LANGUAGE!s}, module.default);
}} catch (error) {{
console.error(`Error importing language module for ${{{_LANGUAGE!s}}}:`, error);
}}
}})();
}}
"""
@classmethod
def get_component_map_custom_code(cls) -> str:
"""Get the custom code for the component.
Returns:
The custom code for the component.
"""
return cls._get_language_registration_hook()
def add_hooks(self) -> list[str | Var]:
"""Add hooks for the component.
Returns:
The hooks for the component.
"""
return [
f"const {_LANGUAGE!s} = {self.language!s}",
self._get_language_registration_hook(),
]
class CodeblockNamespace(ComponentNamespace): class CodeblockNamespace(ComponentNamespace):
"""Namespace for the CodeBlock component.""" """Namespace for the CodeBlock component."""

View File

@ -4,13 +4,13 @@
# This file was generated by `reflex/utils/pyi_generator.py`! # This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------ # ------------------------------------------------------
import dataclasses import dataclasses
from typing import Any, Callable, ClassVar, Dict, Literal, Optional, Union, overload 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.constants.colors import Color from reflex.constants.colors import Color
from reflex.event import EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.utils.imports import ImportDict
from reflex.vars.base import Var from reflex.vars.base import Var
LiteralCodeLanguage = Literal[ LiteralCodeLanguage = Literal[
@ -349,15 +349,12 @@ for theme_name in dir(Theme):
continue continue
setattr(Theme, theme_name, getattr(Theme, theme_name)._replace(_var_type=Theme)) setattr(Theme, theme_name, getattr(Theme, theme_name)._replace(_var_type=Theme))
class CodeBlock(Component): class CodeBlock(Component, MarkdownComponentMap):
def add_imports(self) -> ImportDict: ...
@overload @overload
@classmethod @classmethod
def create( # type: ignore def create( # type: ignore
cls, cls,
*children, *children,
can_copy: Optional[bool] = False,
copy_button: Optional[Union[Component, bool]] = None,
theme: Optional[Union[Theme, Var[Union[Theme, str]], str]] = None, theme: Optional[Union[Theme, Var[Union[Theme, str]], str]] = None,
language: Optional[ language: Optional[
Union[ Union[
@ -933,55 +930,35 @@ class CodeBlock(Component):
wrap_long_lines: Optional[Union[Var[bool], bool]] = None, wrap_long_lines: Optional[Union[Var[bool], bool]] = None,
custom_style: Optional[Dict[str, Union[str, Var, Color]]] = None, custom_style: Optional[Dict[str, Union[str, Var, Color]]] = None,
code_tag_props: Optional[Union[Dict[str, str], Var[Dict[str, str]]]] = None, code_tag_props: Optional[Union[Dict[str, str], Var[Dict[str, str]]]] = None,
can_copy: Optional[bool] = None,
copy_button: Optional[Union[Component, bool]] = 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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "CodeBlock": ) -> "CodeBlock":
"""Create a text component. """Create a text component.
Args: Args:
*children: The children of the component. *children: The children of the component.
can_copy: Whether a copy button should appears.
copy_button: A custom copy button to override the default one.
theme: The theme to use ("light" or "dark"). theme: The theme to use ("light" or "dark").
language: The language to use. language: The language to use.
code: The code to display. code: The code to display.
@ -990,6 +967,8 @@ class CodeBlock(Component):
wrap_long_lines: Whether to wrap long lines. wrap_long_lines: Whether to wrap long lines.
custom_style: A custom style for the code block. custom_style: A custom style for the code block.
code_tag_props: Props passed down to the code tag. code_tag_props: Props passed down to the code tag.
can_copy: Whether a copy button should appear.
copy_button: A custom copy button to override the default one.
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.
id: The id for the component. id: The id for the component.
@ -1004,6 +983,9 @@ class CodeBlock(Component):
... ...
def add_style(self): ... def add_style(self): ...
@classmethod
def get_component_map_custom_code(cls) -> str: ...
def add_hooks(self) -> list[str | Var]: ...
class CodeblockNamespace(ComponentNamespace): class CodeblockNamespace(ComponentNamespace):
themes = Theme themes = Theme
@ -1011,8 +993,6 @@ class CodeblockNamespace(ComponentNamespace):
@staticmethod @staticmethod
def __call__( def __call__(
*children, *children,
can_copy: Optional[bool] = False,
copy_button: Optional[Union[Component, bool]] = None,
theme: Optional[Union[Theme, Var[Union[Theme, str]], str]] = None, theme: Optional[Union[Theme, Var[Union[Theme, str]], str]] = None,
language: Optional[ language: Optional[
Union[ Union[
@ -1588,55 +1568,35 @@ class CodeblockNamespace(ComponentNamespace):
wrap_long_lines: Optional[Union[Var[bool], bool]] = None, wrap_long_lines: Optional[Union[Var[bool], bool]] = None,
custom_style: Optional[Dict[str, Union[str, Var, Color]]] = None, custom_style: Optional[Dict[str, Union[str, Var, Color]]] = None,
code_tag_props: Optional[Union[Dict[str, str], Var[Dict[str, str]]]] = None, code_tag_props: Optional[Union[Dict[str, str], Var[Dict[str, str]]]] = None,
can_copy: Optional[bool] = None,
copy_button: Optional[Union[Component, bool]] = 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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "CodeBlock": ) -> "CodeBlock":
"""Create a text component. """Create a text component.
Args: Args:
*children: The children of the component. *children: The children of the component.
can_copy: Whether a copy button should appears.
copy_button: A custom copy button to override the default one.
theme: The theme to use ("light" or "dark"). theme: The theme to use ("light" or "dark").
language: The language to use. language: The language to use.
code: The code to display. code: The code to display.
@ -1645,6 +1605,8 @@ class CodeblockNamespace(ComponentNamespace):
wrap_long_lines: Whether to wrap long lines. wrap_long_lines: Whether to wrap long lines.
custom_style: A custom style for the code block. custom_style: A custom style for the code block.
code_tag_props: Props passed down to the code tag. code_tag_props: Props passed down to the code tag.
can_copy: Whether a copy button should appear.
copy_button: A custom copy button to override the default one.
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.
id: The id for the component. id: The id for the component.

View File

@ -3,12 +3,14 @@
from __future__ import annotations from __future__ import annotations
from enum import Enum from enum import Enum
from typing import Any, Dict, List, Literal, Optional, Union from typing import Any, Dict, List, Literal, Optional, Tuple, 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
from reflex.components.literals import LiteralRowMarker from reflex.components.literals import LiteralRowMarker
from reflex.event import EventHandler from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
from reflex.utils import console, format, types from reflex.utils import console, format, types
from reflex.utils.imports import ImportDict, ImportVar from reflex.utils.imports import ImportDict, ImportVar
from reflex.utils.serializers import serializer from reflex.utils.serializers import serializer
@ -49,27 +51,6 @@ class GridColumnIcons(Enum):
VideoUri = "video_uri" VideoUri = "video_uri"
# @serializer
# def serialize_gridcolumn_icon(icon: GridColumnIcons) -> str:
# """Serialize grid column icon.
# Args:
# icon: the Icon to serialize.
# Returns:
# The serialized value.
# """
# return "prefix" + str(icon)
# class DataEditorColumn(Base):
# """Column."""
# title: str
# id: Optional[str] = None
# type_: str = "str"
class DataEditorTheme(Base): class DataEditorTheme(Base):
"""The theme for the DataEditor component.""" """The theme for the DataEditor component."""
@ -107,17 +88,76 @@ class DataEditorTheme(Base):
text_medium: Optional[str] = None text_medium: Optional[str] = None
def on_edit_spec(pos, data: dict[str, Any]): class Bounds(TypedDict):
"""The on edit spec function. """The bounds of the group header."""
Args: x: int
pos: The position of the edit event. y: int
data: The data of the edit event. width: int
height: int
Returns:
The position and data. class CompatSelection(TypedDict):
""" """The selection."""
return [pos, data]
items: list
class Rectangle(TypedDict):
"""The bounds of the group header."""
x: int
y: int
width: int
height: int
class GridSelectionCurrent(TypedDict):
"""The current selection."""
cell: tuple[int, int]
range: Rectangle
rangeStack: list[Rectangle]
class GridSelection(TypedDict):
"""The grid selection."""
current: Optional[GridSelectionCurrent]
columns: CompatSelection
rows: CompatSelection
class GroupHeaderClickedEventArgs(TypedDict):
"""The arguments for the group header clicked event."""
kind: str
group: str
location: tuple[int, int]
bounds: Bounds
isEdge: bool
shiftKey: bool
ctrlKey: bool
metaKey: bool
isTouch: bool
localEventX: int
localEventY: int
button: int
buttons: int
scrollEdge: tuple[int, int]
class GridCell(TypedDict):
"""The grid cell."""
span: Optional[List[int]]
class GridColumn(TypedDict):
"""The grid column."""
title: str
group: Optional[str]
class DataEditor(NoSSRComponent): class DataEditor(NoSSRComponent):
@ -125,10 +165,9 @@ class DataEditor(NoSSRComponent):
tag = "DataEditor" tag = "DataEditor"
is_default = True is_default = True
library: str = "@glideapps/glide-data-grid@^5.3.0" library: str = "@glideapps/glide-data-grid@^6.0.3"
lib_dependencies: List[str] = [ lib_dependencies: List[str] = [
"lodash@^4.17.21", "lodash@^4.17.21",
"marked@^4.0.10",
"react-responsive-carousel@^3.2.7", "react-responsive-carousel@^3.2.7",
] ]
@ -145,7 +184,7 @@ class DataEditor(NoSSRComponent):
get_cell_content: Var[str] get_cell_content: Var[str]
# Allow selection for copying. # Allow selection for copying.
get_cell_for_selection: Var[bool] get_cells_for_selection: Var[bool]
# Allow paste. # Allow paste.
on_paste: Var[bool] on_paste: Var[bool]
@ -169,7 +208,7 @@ class DataEditor(NoSSRComponent):
header_height: Var[int] header_height: Var[int]
# Additional header icons: # Additional header icons:
# header_icons: Var[Any] # (TODO: must be a map of name: svg) # header_icons: Var[Any] # (TODO: must be a map of name: svg) #noqa: ERA001
# The maximum width a column can be automatically sized to. # The maximum width a column can be automatically sized to.
max_column_auto_width: Var[int] max_column_auto_width: Var[int]
@ -223,52 +262,58 @@ class DataEditor(NoSSRComponent):
theme: Var[Union[DataEditorTheme, Dict]] theme: Var[Union[DataEditorTheme, Dict]]
# Fired when a cell is activated. # Fired when a cell is activated.
on_cell_activated: EventHandler[lambda pos: [pos]] on_cell_activated: EventHandler[passthrough_event_spec(Tuple[int, int])]
# Fired when a cell is clicked. # Fired when a cell is clicked.
on_cell_clicked: EventHandler[lambda pos: [pos]] on_cell_clicked: EventHandler[passthrough_event_spec(Tuple[int, int])]
# Fired when a cell is right-clicked. # Fired when a cell is right-clicked.
on_cell_context_menu: EventHandler[lambda pos: [pos]] on_cell_context_menu: EventHandler[passthrough_event_spec(Tuple[int, int])]
# Fired when a cell is edited. # Fired when a cell is edited.
on_cell_edited: EventHandler[on_edit_spec] on_cell_edited: EventHandler[passthrough_event_spec(Tuple[int, int], GridCell)]
# Fired when a group header is clicked. # Fired when a group header is clicked.
on_group_header_clicked: EventHandler[on_edit_spec] on_group_header_clicked: EventHandler[
passthrough_event_spec(Tuple[int, int], GridCell)
]
# Fired when a group header is right-clicked. # Fired when a group header is right-clicked.
on_group_header_context_menu: EventHandler[lambda grp_idx, data: [grp_idx, data]] on_group_header_context_menu: EventHandler[
passthrough_event_spec(int, GroupHeaderClickedEventArgs)
]
# Fired when a group header is renamed. # Fired when a group header is renamed.
on_group_header_renamed: EventHandler[lambda idx, val: [idx, val]] on_group_header_renamed: EventHandler[passthrough_event_spec(str, str)]
# Fired when a header is clicked. # Fired when a header is clicked.
on_header_clicked: EventHandler[lambda pos: [pos]] on_header_clicked: EventHandler[passthrough_event_spec(Tuple[int, int])]
# Fired when a header is right-clicked. # Fired when a header is right-clicked.
on_header_context_menu: EventHandler[lambda pos: [pos]] on_header_context_menu: EventHandler[passthrough_event_spec(Tuple[int, int])]
# Fired when a header menu item is clicked. # Fired when a header menu item is clicked.
on_header_menu_click: EventHandler[lambda col, pos: [col, pos]] on_header_menu_click: EventHandler[passthrough_event_spec(int, Rectangle)]
# Fired when an item is hovered. # Fired when an item is hovered.
on_item_hovered: EventHandler[lambda pos: [pos]] on_item_hovered: EventHandler[passthrough_event_spec(Tuple[int, int])]
# Fired when a selection is deleted. # Fired when a selection is deleted.
on_delete: EventHandler[lambda selection: [selection]] on_delete: EventHandler[passthrough_event_spec(GridSelection)]
# Fired when editing is finished. # Fired when editing is finished.
on_finished_editing: EventHandler[lambda new_value, movement: [new_value, movement]] on_finished_editing: EventHandler[
passthrough_event_spec(Union[GridCell, None], tuple[int, int])
]
# Fired when a row is appended. # Fired when a row is appended.
on_row_appended: EventHandler[lambda: []] on_row_appended: EventHandler[no_args_event_spec]
# Fired when the selection is cleared. # Fired when the selection is cleared.
on_selection_cleared: EventHandler[lambda: []] on_selection_cleared: EventHandler[no_args_event_spec]
# Fired when a column is resized. # Fired when a column is resized.
on_column_resize: EventHandler[lambda col, width: [col, width]] on_column_resize: EventHandler[passthrough_event_spec(GridColumn, int)]
def add_imports(self) -> ImportDict: def add_imports(self) -> ImportDict:
"""Add imports for the component. """Add imports for the component.
@ -279,7 +324,7 @@ class DataEditor(NoSSRComponent):
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",
"/utils/helpers/dataeditor.js": ImportVar( "$/utils/helpers/dataeditor.js": ImportVar(
tag="formatDataEditorCells", is_default=False, install=False tag="formatDataEditorCells", is_default=False, install=False
), ),
} }
@ -329,7 +374,7 @@ class DataEditor(NoSSRComponent):
columns = props.get("columns", []) columns = props.get("columns", [])
data = props.get("data", []) data = props.get("data", [])
rows = props.get("rows", None) rows = props.get("rows")
# If rows is not provided, determine from data. # If rows is not provided, determine from data.
if rows is None: if rows is None:
@ -340,10 +385,8 @@ class DataEditor(NoSSRComponent):
props["rows"] = data.length() if isinstance(data, Var) else len(data) props["rows"] = data.length() if isinstance(data, Var) else len(data)
if not isinstance(columns, Var) and len(columns): if not isinstance(columns, Var) and len(columns):
if ( if types.is_dataframe(type(data)) or (
types.is_dataframe(type(data)) isinstance(data, Var) and types.is_dataframe(data._var_type)
or isinstance(data, Var)
and types.is_dataframe(data._var_type)
): ):
raise ValueError( raise ValueError(
"Cannot pass in both a pandas dataframe and columns to the data_editor component." "Cannot pass in both a pandas dataframe and columns to the data_editor component."
@ -359,7 +402,7 @@ class DataEditor(NoSSRComponent):
props["theme"] = DataEditorTheme(**theme) props["theme"] = DataEditorTheme(**theme)
# Allow by default to select a region of cells in the grid. # Allow by default to select a region of cells in the grid.
props.setdefault("get_cell_for_selection", True) props.setdefault("get_cells_for_selection", True)
# Disable on_paste by default if not provided. # Disable on_paste by default if not provided.
props.setdefault("on_paste", False) props.setdefault("on_paste", False)

View File

@ -4,11 +4,13 @@
# 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, Callable, Dict, List, Literal, Optional, Union, overload from typing import Any, Dict, List, Literal, Optional, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, 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
@ -76,7 +78,53 @@ class DataEditorTheme(Base):
text_light: Optional[str] text_light: Optional[str]
text_medium: Optional[str] text_medium: Optional[str]
def on_edit_spec(pos, data: dict[str, Any]): ... class Bounds(TypedDict):
x: int
y: int
width: int
height: int
class CompatSelection(TypedDict):
items: list
class Rectangle(TypedDict):
x: int
y: int
width: int
height: int
class GridSelectionCurrent(TypedDict):
cell: tuple[int, int]
range: Rectangle
rangeStack: list[Rectangle]
class GridSelection(TypedDict):
current: Optional[GridSelectionCurrent]
columns: CompatSelection
rows: CompatSelection
class GroupHeaderClickedEventArgs(TypedDict):
kind: str
group: str
location: tuple[int, int]
bounds: Bounds
isEdge: bool
shiftKey: bool
ctrlKey: bool
metaKey: bool
isTouch: bool
localEventX: int
localEventY: int
button: int
buttons: int
scrollEdge: tuple[int, int]
class GridCell(TypedDict):
span: Optional[List[int]]
class GridColumn(TypedDict):
title: str
group: Optional[str]
class DataEditor(NoSSRComponent): class DataEditor(NoSSRComponent):
def add_imports(self) -> ImportDict: ... def add_imports(self) -> ImportDict: ...
@ -92,7 +140,7 @@ class DataEditor(NoSSRComponent):
] = None, ] = None,
data: Optional[Union[List[List[Any]], Var[List[List[Any]]]]] = None, data: Optional[Union[List[List[Any]], Var[List[List[Any]]]]] = None,
get_cell_content: Optional[Union[Var[str], str]] = None, get_cell_content: Optional[Union[Var[str], str]] = None,
get_cell_for_selection: Optional[Union[Var[bool], bool]] = None, get_cells_for_selection: Optional[Union[Var[bool], bool]] = None,
on_paste: Optional[Union[Var[bool], bool]] = None, on_paste: Optional[Union[Var[bool], bool]] = None,
draw_focus_ring: Optional[Union[Var[bool], bool]] = None, draw_focus_ring: Optional[Union[Var[bool], bool]] = None,
fixed_shadow_x: Optional[Union[Var[bool], bool]] = None, fixed_shadow_x: Optional[Union[Var[bool], bool]] = None,
@ -134,88 +182,94 @@ class DataEditor(NoSSRComponent):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_cell_activated: Optional[ on_cell_activated: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]]
] = None, ] = None,
on_cell_clicked: Optional[ on_cell_clicked: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]]
] = None, ] = None,
on_cell_context_menu: Optional[ on_cell_context_menu: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]]
] = None, ] = None,
on_cell_edited: Optional[ on_cell_edited: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[
EventType[[], BASE_STATE],
EventType[[tuple[int, int]], BASE_STATE],
EventType[[tuple[int, int], GridCell], BASE_STATE],
]
] = None, ] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_column_resize: Optional[ on_column_resize: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[
EventType[[], BASE_STATE],
EventType[[GridColumn], BASE_STATE],
EventType[[GridColumn, int], BASE_STATE],
]
] = None, ] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_delete: Optional[
] = None, Union[EventType[[], BASE_STATE], EventType[[GridSelection], BASE_STATE]]
on_delete: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_double_click: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None, ] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None,
on_finished_editing: Optional[ on_finished_editing: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[
EventType[[], BASE_STATE],
EventType[[Union[GridCell, None]], BASE_STATE],
EventType[[Union[GridCell, None], tuple[int, int]], BASE_STATE],
]
] = None, ] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_group_header_clicked: Optional[ on_group_header_clicked: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[
EventType[[], BASE_STATE],
EventType[[tuple[int, int]], BASE_STATE],
EventType[[tuple[int, int], GridCell], BASE_STATE],
]
] = None, ] = None,
on_group_header_context_menu: Optional[ on_group_header_context_menu: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[
EventType[[], BASE_STATE],
EventType[[int], BASE_STATE],
EventType[[int, GroupHeaderClickedEventArgs], BASE_STATE],
]
] = None, ] = None,
on_group_header_renamed: Optional[ on_group_header_renamed: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[
EventType[[], BASE_STATE],
EventType[[str], BASE_STATE],
EventType[[str, str], BASE_STATE],
]
] = None, ] = None,
on_header_clicked: Optional[ on_header_clicked: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]]
] = None, ] = None,
on_header_context_menu: Optional[ on_header_context_menu: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]]
] = None, ] = None,
on_header_menu_click: Optional[ on_header_menu_click: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[
EventType[[], BASE_STATE],
EventType[[int], BASE_STATE],
EventType[[int, Rectangle], BASE_STATE],
]
] = None, ] = None,
on_item_hovered: Optional[ on_item_hovered: Optional[
Union[EventHandler, EventSpec, list, Callable, Var] Union[EventType[[], BASE_STATE], EventType[[tuple[int, int]], BASE_STATE]]
] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_row_appended: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_selection_cleared: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None, ] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_row_appended: Optional[EventType[[], BASE_STATE]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
on_selection_cleared: Optional[EventType[[], BASE_STATE]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
**props, **props,
) -> "DataEditor": ) -> "DataEditor":
"""Create the DataEditor component. """Create the DataEditor component.
@ -226,7 +280,7 @@ class DataEditor(NoSSRComponent):
columns: Headers of the columns for the data grid. columns: Headers of the columns for the data grid.
data: The data. data: The data.
get_cell_content: The name of the callback used to find the data to display. get_cell_content: The name of the callback used to find the data to display.
get_cell_for_selection: Allow selection for copying. get_cells_for_selection: Allow selection for copying.
on_paste: Allow paste. on_paste: Allow paste.
draw_focus_ring: Controls the drawing of the focus ring. draw_focus_ring: Controls the drawing of the focus ring.
fixed_shadow_x: Enables or disables the overlay shadow when scrolling horizontally. fixed_shadow_x: Enables or disables the overlay shadow when scrolling horizontally.
@ -234,7 +288,7 @@ class DataEditor(NoSSRComponent):
freeze_columns: The number of columns which should remain in place when scrolling horizontally. Doesn't include rowMarkers. freeze_columns: The number of columns which should remain in place when scrolling horizontally. Doesn't include rowMarkers.
group_header_height: Controls the header of the group header row. group_header_height: Controls the header of the group header row.
header_height: Controls the height of the header row. header_height: Controls the height of the header row.
max_column_auto_width: Additional header icons: header_icons: Var[Any] # (TODO: must be a map of name: svg) The maximum width a column can be automatically sized to. max_column_auto_width: The maximum width a column can be automatically sized to.
max_column_width: The maximum width a column can be resized to. max_column_width: The maximum width a column can be resized to.
min_column_width: The minimum width a column can be resized to. min_column_width: The minimum width a column can be resized to.
row_height: Determins the height of each row. row_height: Determins the height of each row.
@ -251,6 +305,22 @@ class DataEditor(NoSSRComponent):
scroll_offset_x: Initial scroll offset on the horizontal axis. scroll_offset_x: Initial scroll offset on the horizontal axis.
scroll_offset_y: Initial scroll offset on the vertical axis. scroll_offset_y: Initial scroll offset on the vertical axis.
theme: global theme theme: global theme
on_cell_activated: Fired when a cell is activated.
on_cell_clicked: Fired when a cell is clicked.
on_cell_context_menu: Fired when a cell is right-clicked.
on_cell_edited: Fired when a cell is edited.
on_group_header_clicked: Fired when a group header is clicked.
on_group_header_context_menu: Fired when a group header is right-clicked.
on_group_header_renamed: Fired when a group header is renamed.
on_header_clicked: Fired when a header is clicked.
on_header_context_menu: Fired when a header is right-clicked.
on_header_menu_click: Fired when a header menu item is clicked.
on_item_hovered: Fired when an item is hovered.
on_delete: Fired when a selection is deleted.
on_finished_editing: Fired when editing is finished.
on_row_appended: Fired when a row is appended.
on_selection_cleared: Fired when the selection is cleared.
on_column_resize: Fired when a column is resized.
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.
id: The id for the component. id: The id for the component.

View File

@ -1,22 +1,23 @@
"""A Reflex logo component.""" """A Reflex logo component."""
from typing import Union
import reflex as rx import reflex as rx
def logo(**props): def svg_logo(color: Union[str, rx.Var[str]] = rx.color_mode_cond("#110F1F", "white")):
"""A Reflex logo. """A Reflex logo SVG.
Args: Args:
**props: The props to pass to the component. color: The color of the logo.
Returns: Returns:
The logo component. The Reflex logo SVG.
""" """
def logo_path(d): def logo_path(d):
return rx.el.svg.path( return rx.el.svg.path(
d=d, d=d,
fill=rx.color_mode_cond("#110F1F", "white"),
) )
paths = [ paths = [
@ -28,18 +29,30 @@ def logo(**props):
"M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z", "M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z",
] ]
return rx.el.svg(
*[logo_path(d) for d in paths],
width="56",
height="12",
viewBox="0 0 56 12",
fill=color,
xmlns="http://www.w3.org/2000/svg",
)
def logo(**props):
"""A Reflex logo.
Args:
**props: The props to pass to the component.
Returns:
The logo component.
"""
return rx.center( return rx.center(
rx.link( rx.link(
rx.hstack( rx.hstack(
"Built with ", "Built with ",
rx.el.svg( svg_logo(),
*[logo_path(d) for d in paths],
width="56",
height="12",
viewBox="0 0 56 12",
fill="none",
xmlns="http://www.w3.org/2000/svg",
),
text_align="center", text_align="center",
align="center", align="center",
padding="1em", padding="1em",

View File

@ -0,0 +1,846 @@
"""Shiki syntax hghlighter component."""
from __future__ import annotations
import re
from collections import defaultdict
from typing import Any, Literal, Optional, Union
from reflex.base import Base
from reflex.components.component import Component, ComponentNamespace
from reflex.components.core.colors import color
from reflex.components.core.cond import color_mode_cond
from reflex.components.el.elements.forms import Button
from reflex.components.lucide.icon import Icon
from reflex.components.markdown.markdown import MarkdownComponentMap
from reflex.components.props import NoExtrasAllowedProps
from reflex.components.radix.themes.layout.box import Box
from reflex.event import run_script, set_clipboard
from reflex.style import Style
from reflex.utils.exceptions import VarTypeError
from reflex.utils.imports import ImportVar
from reflex.vars.base import LiteralVar, Var
from reflex.vars.function import FunctionStringVar
from reflex.vars.sequence import StringVar, string_replace_operation
def copy_script() -> Any:
"""Copy script for the code block and modify the child SVG element.
Returns:
Any: The result of calling the script.
"""
return run_script(
"""
// Event listener for the parent click
document.addEventListener('click', function(event) {
// Find the closest button (parent element)
const parent = event.target.closest('button');
// If the parent is found
if (parent) {
// Find the SVG element within the parent
const svgIcon = parent.querySelector('svg');
// If the SVG exists, proceed with the script
if (svgIcon) {
const originalPath = svgIcon.innerHTML;
const checkmarkPath = '<polyline points="20 6 9 17 4 12"></polyline>'; // Checkmark SVG path
function transition(element, scale, opacity) {
element.style.transform = `scale(${scale})`;
element.style.opacity = opacity;
}
// Animate the SVG
transition(svgIcon, 0, '0');
setTimeout(() => {
svgIcon.innerHTML = checkmarkPath; // Replace content with checkmark
svgIcon.setAttribute('viewBox', '0 0 24 24'); // Adjust viewBox if necessary
transition(svgIcon, 1, '1');
setTimeout(() => {
transition(svgIcon, 0, '0');
setTimeout(() => {
svgIcon.innerHTML = originalPath; // Restore original SVG content
transition(svgIcon, 1, '1');
}, 125);
}, 600);
}, 125);
} else {
// console.error('SVG element not found within the parent.');
}
} else {
// console.error('Parent element not found.');
}
})
"""
)
SHIKIJS_TRANSFORMER_FNS = {
"transformerNotationDiff",
"transformerNotationHighlight",
"transformerNotationWordHighlight",
"transformerNotationFocus",
"transformerNotationErrorLevel",
"transformerRenderWhitespace",
"transformerMetaHighlight",
"transformerMetaWordHighlight",
"transformerCompactLineOptions",
# TODO: this transformer when included adds a weird behavior which removes other code lines. Need to figure out why.
# "transformerRemoveLineBreak",
"transformerRemoveNotationEscape",
}
LINE_NUMBER_STYLING = {
"code": {
"counter-reset": "step",
"counter-increment": "step 0",
"display": "grid",
"line-height": "1.7",
"font-size": "0.875em",
},
"code .line::before": {
"content": "counter(step)",
"counter-increment": "step",
"width": "1rem",
"margin-right": "1.5rem",
"display": "inline-block",
"text-align": "right",
"color": "rgba(115,138,148,.4)",
},
}
BOX_PARENT_STYLING = {
"pre": {
"margin": "0",
"padding": "24px",
"background": "transparent",
"overflow-x": "auto",
"border-radius": "6px",
},
}
THEME_MAPPING = {
"light": "one-light",
"dark": "one-dark-pro",
"a11y-dark": "github-dark",
}
LANGUAGE_MAPPING = {"bash": "shellscript"}
LiteralCodeLanguage = Literal[
"abap",
"actionscript-3",
"ada",
"angular-html",
"angular-ts",
"apache",
"apex",
"apl",
"applescript",
"ara",
"asciidoc",
"asm",
"astro",
"awk",
"ballerina",
"bat",
"beancount",
"berry",
"bibtex",
"bicep",
"blade",
"c",
"cadence",
"clarity",
"clojure",
"cmake",
"cobol",
"codeowners",
"codeql",
"coffee",
"common-lisp",
"coq",
"cpp",
"crystal",
"csharp",
"css",
"csv",
"cue",
"cypher",
"d",
"dart",
"dax",
"desktop",
"diff",
"docker",
"dotenv",
"dream-maker",
"edge",
"elixir",
"elm",
"emacs-lisp",
"erb",
"erlang",
"fennel",
"fish",
"fluent",
"fortran-fixed-form",
"fortran-free-form",
"fsharp",
"gdresource",
"gdscript",
"gdshader",
"genie",
"gherkin",
"git-commit",
"git-rebase",
"gleam",
"glimmer-js",
"glimmer-ts",
"glsl",
"gnuplot",
"go",
"graphql",
"groovy",
"hack",
"haml",
"handlebars",
"haskell",
"haxe",
"hcl",
"hjson",
"hlsl",
"html",
"html-derivative",
"http",
"hxml",
"hy",
"imba",
"ini",
"java",
"javascript",
"jinja",
"jison",
"json",
"json5",
"jsonc",
"jsonl",
"jsonnet",
"jssm",
"jsx",
"julia",
"kotlin",
"kusto",
"latex",
"lean",
"less",
"liquid",
"log",
"logo",
"lua",
"luau",
"make",
"markdown",
"marko",
"matlab",
"mdc",
"mdx",
"mermaid",
"mojo",
"move",
"narrat",
"nextflow",
"nginx",
"nim",
"nix",
"nushell",
"objective-c",
"objective-cpp",
"ocaml",
"pascal",
"perl",
"php",
"plain",
"plsql",
"po",
"postcss",
"powerquery",
"powershell",
"prisma",
"prolog",
"proto",
"pug",
"puppet",
"purescript",
"python",
"qml",
"qmldir",
"qss",
"r",
"racket",
"raku",
"razor",
"reg",
"regexp",
"rel",
"riscv",
"rst",
"ruby",
"rust",
"sas",
"sass",
"scala",
"scheme",
"scss",
"shaderlab",
"shellscript",
"shellsession",
"smalltalk",
"solidity",
"soy",
"sparql",
"splunk",
"sql",
"ssh-config",
"stata",
"stylus",
"svelte",
"swift",
"system-verilog",
"systemd",
"tasl",
"tcl",
"templ",
"terraform",
"tex",
"toml",
"ts-tags",
"tsv",
"tsx",
"turtle",
"twig",
"typescript",
"typespec",
"typst",
"v",
"vala",
"vb",
"verilog",
"vhdl",
"viml",
"vue",
"vue-html",
"vyper",
"wasm",
"wenyan",
"wgsl",
"wikitext",
"wolfram",
"xml",
"xsl",
"yaml",
"zenscript",
"zig",
]
LiteralCodeTheme = Literal[
"andromeeda",
"aurora-x",
"ayu-dark",
"catppuccin-frappe",
"catppuccin-latte",
"catppuccin-macchiato",
"catppuccin-mocha",
"dark-plus",
"dracula",
"dracula-soft",
"everforest-dark",
"everforest-light",
"github-dark",
"github-dark-default",
"github-dark-dimmed",
"github-dark-high-contrast",
"github-light",
"github-light-default",
"github-light-high-contrast",
"houston",
"laserwave",
"light-plus",
"material-theme",
"material-theme-darker",
"material-theme-lighter",
"material-theme-ocean",
"material-theme-palenight",
"min-dark",
"min-light",
"monokai",
"night-owl",
"nord",
"one-dark-pro",
"one-light",
"plastic",
"poimandres",
"red",
# rose-pine themes dont work with the current version of shikijs transformers
# https://github.com/shikijs/shiki/issues/730
"rose-pine",
"rose-pine-dawn",
"rose-pine-moon",
"slack-dark",
"slack-ochin",
"snazzy-light",
"solarized-dark",
"solarized-light",
"synthwave-84",
"tokyo-night",
"vesper",
"vitesse-black",
"vitesse-dark",
"vitesse-light",
]
class Position(NoExtrasAllowedProps):
"""Position of the decoration."""
line: int
character: int
class ShikiDecorations(NoExtrasAllowedProps):
"""Decorations for the code block."""
start: Union[int, Position]
end: Union[int, Position]
tag_name: str = "span"
properties: dict[str, Any] = {}
always_wrap: bool = False
class ShikiBaseTransformers(Base):
"""Base for creating transformers."""
library: str
fns: list[FunctionStringVar]
style: Optional[Style]
class ShikiJsTransformer(ShikiBaseTransformers):
"""A Wrapped shikijs transformer."""
library: str = "@shikijs/transformers"
fns: list[FunctionStringVar] = [
FunctionStringVar.create(fn) for fn in SHIKIJS_TRANSFORMER_FNS
]
style: Optional[Style] = Style(
{
"code": {"line-height": "1.7", "font-size": "0.875em", "display": "grid"},
# Diffs
".diff": {
"margin": "0 -24px",
"padding": "0 24px",
"width": "calc(100% + 48px)",
"display": "inline-block",
},
".diff.add": {
"background-color": "rgba(16, 185, 129, .14)",
"position": "relative",
},
".diff.remove": {
"background-color": "rgba(244, 63, 94, .14)",
"opacity": "0.7",
"position": "relative",
},
".diff.remove:after": {
"position": "absolute",
"left": "10px",
"content": "'-'",
"color": "#b34e52",
},
".diff.add:after": {
"position": "absolute",
"left": "10px",
"content": "'+'",
"color": "#18794e",
},
# Highlight
".highlighted": {
"background-color": "rgba(142, 150, 170, .14)",
"margin": "0 -24px",
"padding": "0 24px",
"width": "calc(100% + 48px)",
"display": "inline-block",
},
".highlighted.error": {
"background-color": "rgba(244, 63, 94, .14)",
},
".highlighted.warning": {
"background-color": "rgba(234, 179, 8, .14)",
},
# Highlighted Word
".highlighted-word": {
"background-color": color("gray", 2),
"border": f"1px solid {color('gray', 5)}",
"padding": "1px 3px",
"margin": "-1px -3px",
"border-radius": "4px",
},
# Focused Lines
".has-focused .line:not(.focused)": {
"opacity": "0.7",
"filter": "blur(0.095rem)",
"transition": "filter .35s, opacity .35s",
},
".has-focused:hover .line:not(.focused)": {
"opacity": "1",
"filter": "none",
},
# White Space
# ".tab, .space": {
# "position": "relative", # noqa: ERA001
# },
# ".tab::before": {
# "content": "'⇥'", # noqa: ERA001
# "position": "absolute", # noqa: ERA001
# "opacity": "0.3",# noqa: ERA001
# },
# ".space::before": {
# "content": "'·'", # noqa: ERA001
# "position": "absolute", # noqa: ERA001
# "opacity": "0.3", # noqa: ERA001
# },
}
)
def __init__(self, **kwargs):
"""Initialize the transformer.
Args:
kwargs: Kwargs to initialize the props.
"""
fns = kwargs.pop("fns", None)
style = kwargs.pop("style", None)
if fns:
kwargs["fns"] = [
(
FunctionStringVar.create(x)
if not isinstance(x, FunctionStringVar)
else x
)
for x in fns
]
if style:
kwargs["style"] = Style(style)
super().__init__(**kwargs)
class ShikiCodeBlock(Component, MarkdownComponentMap):
"""A Code block."""
library = "/components/shiki/code"
tag = "Code"
alias = "ShikiCode"
lib_dependencies: list[str] = ["shiki"]
# The language to use.
language: Var[LiteralCodeLanguage] = Var.create("python")
# The theme to use ("light" or "dark").
theme: Var[LiteralCodeTheme] = Var.create("one-light")
# The set of themes to use for different modes.
themes: Var[Union[list[dict[str, Any]], dict[str, str]]]
# The code to display.
code: Var[str]
# The transformers to use for the syntax highlighter.
transformers: Var[list[Union[ShikiBaseTransformers, dict[str, Any]]]] = Var.create(
[]
)
# The decorations to use for the syntax highlighter.
decorations: Var[list[ShikiDecorations]] = Var.create([])
@classmethod
def create(
cls,
*children,
**props,
) -> Component:
"""Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
Args:
*children: The children of the component.
**props: The props to pass to the component.
Returns:
The code block component.
"""
# Separate props for the code block and the wrapper
code_block_props = {}
code_wrapper_props = {}
decorations = props.pop("decorations", [])
class_props = cls.get_props()
# Distribute props between the code block and wrapper
for key, value in props.items():
(code_block_props if key in class_props else code_wrapper_props)[key] = (
value
)
# cast decorations into ShikiDecorations.
decorations = [
ShikiDecorations(**decoration)
if not isinstance(decoration, ShikiDecorations)
else decoration
for decoration in decorations
]
code_block_props["decorations"] = decorations
code_block_props["code"] = children[0]
code_block = super().create(**code_block_props)
transformer_styles = {}
# Collect styles from transformers and wrapper
for transformer in code_block.transformers._var_value: # type: ignore
if isinstance(transformer, ShikiBaseTransformers) and transformer.style:
transformer_styles.update(transformer.style)
transformer_styles.update(code_wrapper_props.pop("style", {}))
return Box.create(
code_block,
*children[1:],
style=Style({**transformer_styles, **BOX_PARENT_STYLING}),
**code_wrapper_props,
)
def add_imports(self) -> dict[str, list[str]]:
"""Add the necessary imports.
We add all referenced transformer functions as imports from their corresponding
libraries.
Returns:
Imports for the component.
"""
imports = defaultdict(list)
for transformer in self.transformers._var_value:
if isinstance(transformer, ShikiBaseTransformers):
imports[transformer.library].extend(
[ImportVar(tag=str(fn)) for fn in transformer.fns]
)
(
self.lib_dependencies.append(transformer.library)
if transformer.library not in self.lib_dependencies
else None
)
return imports
@classmethod
def create_transformer(cls, library: str, fns: list[str]) -> ShikiBaseTransformers:
"""Create a transformer from a third party library.
Args:
library: The name of the library.
fns: The str names of the functions/callables to invoke from the library.
Returns:
A transformer for the specified library.
Raises:
ValueError: If a supplied function name is not valid str.
"""
if any(not isinstance(fn_name, str) for fn_name in fns):
raise ValueError(
f"the function names should be str names of functions in the specified transformer: {library!r}"
)
return ShikiBaseTransformers( # type: ignore
library=library, fns=[FunctionStringVar.create(fn) for fn in fns]
)
def _render(self, props: dict[str, Any] | None = None):
"""Renders the component with the given properties, processing transformers if present.
Args:
props: Optional properties to pass to the render function.
Returns:
Rendered component output.
"""
# Ensure props is initialized from class attributes if not provided
props = props or {
attr.rstrip("_"): getattr(self, attr) for attr in self.get_props()
}
# Extract transformers and apply transformations
transformers = props.get("transformers")
if transformers is not None:
transformed_values = self._process_transformers(transformers._var_value)
props["transformers"] = LiteralVar.create(transformed_values)
return super()._render(props)
def _process_transformers(self, transformer_list: list) -> list:
"""Processes a list of transformers, applying transformations where necessary.
Args:
transformer_list: List of transformer objects or values.
Returns:
list: A list of transformed values.
"""
processed = []
for transformer in transformer_list:
if isinstance(transformer, ShikiBaseTransformers):
processed.extend(fn.call() for fn in transformer.fns)
else:
processed.append(transformer)
return processed
class ShikiHighLevelCodeBlock(ShikiCodeBlock):
"""High level component for the shiki syntax highlighter."""
# If this is enabled, the default transformers(shikijs transformer) will be used.
use_transformers: Var[bool]
# If this is enabled line numbers will be shown next to the code block.
show_line_numbers: Var[bool]
# Whether a copy button should appear.
can_copy: bool = False
# copy_button: A custom copy button to override the default one.
copy_button: Optional[Union[Component, bool]] = None
@classmethod
def create(
cls,
*children,
**props,
) -> Component:
"""Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
Args:
*children: The children of the component.
**props: The props to pass to the component.
Returns:
The code block component.
"""
use_transformers = props.pop("use_transformers", False)
show_line_numbers = props.pop("show_line_numbers", False)
language = props.pop("language", None)
can_copy = props.pop("can_copy", False)
copy_button = props.pop("copy_button", None)
if use_transformers:
props["transformers"] = [ShikiJsTransformer()]
if language is not None:
props["language"] = cls._map_languages(language)
# line numbers are generated via css
if show_line_numbers:
props["style"] = {**LINE_NUMBER_STYLING, **props.get("style", {})}
theme = props.pop("theme", None)
props["theme"] = props["theme"] = (
cls._map_themes(theme)
if theme is not None
else color_mode_cond( # Default color scheme responds to global color mode.
light="one-light",
dark="one-dark-pro",
)
)
if can_copy:
code = children[0]
copy_button = ( # type: ignore
copy_button
if copy_button is not None
else Button.create(
Icon.create(tag="copy", size=16, color=color("gray", 11)),
on_click=[
set_clipboard(cls._strip_transformer_triggers(code)), # type: ignore
copy_script(),
],
style=Style(
{
"position": "absolute",
"top": "4px",
"right": "4px",
"background": color("gray", 3),
"border": "1px solid",
"border-color": color("gray", 5),
"border-radius": "6px",
"padding": "5px",
"opacity": "1",
"cursor": "pointer",
"_hover": {
"background": color("gray", 4),
},
"transition": "background 0.250s ease-out",
"&>svg": {
"transition": "transform 0.250s ease-out, opacity 0.250s ease-out",
},
"_active": {
"background": color("gray", 5),
},
}
),
)
)
if copy_button:
return ShikiCodeBlock.create(
children[0], copy_button, position="relative", **props
)
else:
return ShikiCodeBlock.create(children[0], **props)
@staticmethod
def _map_themes(theme: str) -> str:
if isinstance(theme, str) and theme in THEME_MAPPING:
return THEME_MAPPING[theme]
return theme
@staticmethod
def _map_languages(language: str) -> str:
if isinstance(language, str) and language in LANGUAGE_MAPPING:
return LANGUAGE_MAPPING[language]
return language
@staticmethod
def _strip_transformer_triggers(code: str | StringVar) -> StringVar | str:
if not isinstance(code, (StringVar, str)):
raise VarTypeError(
f"code should be string literal or a StringVar type. Got {type(code)} instead."
)
regex_pattern = r"[\/#]+ *\[!code.*?\]"
if isinstance(code, Var):
return string_replace_operation(
code, StringVar(_js_expr=f"/{regex_pattern}/g", _var_type=str), ""
)
if isinstance(code, str):
return re.sub(regex_pattern, "", code)
class TransformerNamespace(ComponentNamespace):
"""Namespace for the Transformers."""
shikijs = ShikiJsTransformer
class CodeblockNamespace(ComponentNamespace):
"""Namespace for the CodeBlock component."""
root = staticmethod(ShikiCodeBlock.create)
create_transformer = staticmethod(ShikiCodeBlock.create_transformer)
transformers = TransformerNamespace()
__call__ = staticmethod(ShikiHighLevelCodeBlock.create)
code_block = CodeblockNamespace()

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,18 @@
"""Components that are dynamically generated on the backend.""" """Components that are dynamically generated on the backend."""
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.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
from reflex.vars.base import VarData, transform from reflex.vars.base import VarData, transform
if TYPE_CHECKING:
from reflex.components.component import Component
def get_cdn_url(lib: str) -> str: def get_cdn_url(lib: str) -> str:
"""Get the CDN URL for a library. """Get the CDN URL for a library.
@ -19,6 +26,26 @@ def get_cdn_url(lib: str) -> str:
return f"https://cdn.jsdelivr.net/npm/{lib}" + "/+esm" return f"https://cdn.jsdelivr.net/npm/{lib}" + "/+esm"
bundled_libraries = {"react", "@radix-ui/themes", "@emotion/react", "next/link"}
def bundle_library(component: Union["Component", str]):
"""Bundle a library with the component.
Args:
component: The component to bundle the library with.
Raises:
DynamicComponentMissingLibrary: Raised when a dynamic component is missing a library.
"""
if isinstance(component, str):
bundled_libraries.add(component)
return
if component.library is None:
raise DynamicComponentMissingLibrary("Component must have a library to bundle.")
bundled_libraries.add(format_library_name(component.library))
def load_dynamic_serializer(): def load_dynamic_serializer():
"""Load the serializer for dynamic components.""" """Load the serializer for dynamic components."""
# Causes a circular import, so we import here. # Causes a circular import, so we import here.
@ -36,6 +63,9 @@ def load_dynamic_serializer():
""" """
# Causes a circular import, so we import here. # Causes a circular import, so we import here.
from reflex.compiler import templates, utils from reflex.compiler import templates, utils
from reflex.components.base.bare import Bare
component = Bare.create(Var.create(component))
rendered_components = {} rendered_components = {}
# Include dynamic imports in the shared component. # Include dynamic imports in the shared component.
@ -57,20 +87,15 @@ def load_dynamic_serializer():
) )
] = None ] = None
libs_in_window = [ libs_in_window = bundled_libraries
"react",
"@radix-ui/themes",
]
imports = {} imports = {}
for lib, names in component._get_all_imports().items(): for lib, names in component._get_all_imports().items():
formatted_lib_name = format_library_name(lib)
if ( if (
not lib.startswith((".", "/")) not lib.startswith((".", "/", "$/"))
and not lib.startswith("http") and not lib.startswith("http")
and all( and formatted_lib_name not in libs_in_window
not lib.startswith(lib_in_window)
for lib_in_window in libs_in_window
)
): ):
imports[get_cdn_url(lib)] = names imports[get_cdn_url(lib)] = names
else: else:
@ -84,11 +109,11 @@ def load_dynamic_serializer():
# Rewrite imports from `/` to destructure from window # Rewrite imports from `/` to destructure from window
for ix, line in enumerate(module_code_lines[:]): for ix, line in enumerate(module_code_lines[:]):
if line.startswith("import "): if line.startswith("import "):
if 'from "/' in line: if 'from "$/' in line or 'from "/' in line:
module_code_lines[ix] = ( module_code_lines[ix] = (
line.replace("import ", "const ", 1).replace( line.replace("import ", "const ", 1)
" from ", " = window['__reflex'][", 1 .replace(" as ", ": ")
) .replace(" from ", " = window['__reflex'][", 1)
+ "]" + "]"
) )
else: else:
@ -105,10 +130,18 @@ def load_dynamic_serializer():
module_code_lines[ix] = line.replace( module_code_lines[ix] = line.replace(
"export function", "export default function", 1 "export function", "export default function", 1
) )
line_stripped = line.strip()
if line_stripped.startswith("{") and line_stripped.endswith("}"):
module_code_lines[ix] = line_stripped[1:-1]
module_code_lines.insert(0, "const React = window.__reflex.react;") module_code_lines.insert(0, "const React = window.__reflex.react;")
return "//__reflex_evaluate\n" + "\n".join(module_code_lines) return "\n".join(
[
"//__reflex_evaluate",
*module_code_lines,
]
)
@transform @transform
def evaluate_component(js_string: Var[str]) -> Var[Component]: def evaluate_component(js_string: Var[str]) -> Var[Component]:
@ -128,7 +161,7 @@ def load_dynamic_serializer():
merge_var_data=VarData.merge( merge_var_data=VarData.merge(
VarData( VarData(
imports={ imports={
f"/{constants.Dirs.STATE_PATH}": [ f"$/{constants.Dirs.STATE_PATH}": [
imports.ImportVar(tag="evalReactComponent"), imports.ImportVar(tag="evalReactComponent"),
], ],
"react": [ "react": [
@ -140,7 +173,7 @@ def load_dynamic_serializer():
f"const [{unique_var_name}, set_{unique_var_name}] = useState(null);": None, f"const [{unique_var_name}, set_{unique_var_name}] = useState(null);": None,
"useEffect(() => {" "useEffect(() => {"
"let isMounted = true;" "let isMounted = true;"
f"evalReactComponent({str(js_string)})" f"evalReactComponent({js_string!s})"
".then((component) => {" ".then((component) => {"
"if (isMounted) {" "if (isMounted) {"
f"set_{unique_var_name}(component);" f"set_{unique_var_name}(component);"
@ -150,7 +183,7 @@ def load_dynamic_serializer():
"isMounted = false;" "isMounted = false;"
"};" "};"
"}" "}"
f", [{str(js_string)}]);": None, f", [{js_string!s}]);": None,
}, },
), ),
), ),

View File

@ -3,7 +3,9 @@
# This file was generated by `reflex/utils/pyi_generator.py`! # This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------ # ------------------------------------------------------
from . import elements as elements
from .elements.forms import Button as Button from .elements.forms import Button as Button
from .elements.forms import Datalist as Datalist
from .elements.forms import Fieldset as Fieldset from .elements.forms import Fieldset as Fieldset
from .elements.forms import Form as Form from .elements.forms import Form as Form
from .elements.forms import Input as Input from .elements.forms import Input as Input
@ -17,6 +19,7 @@ from .elements.forms import Progress as Progress
from .elements.forms import Select as Select from .elements.forms import Select as Select
from .elements.forms import Textarea as Textarea from .elements.forms import Textarea as Textarea
from .elements.forms import button as button from .elements.forms import button as button
from .elements.forms import datalist as datalist
from .elements.forms import fieldset as fieldset from .elements.forms import fieldset as fieldset
from .elements.forms import form as form from .elements.forms import form as form
from .elements.forms import input as input from .elements.forms import input as input

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, Callable, 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 EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -21,42 +21,22 @@ class Element(Component):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Element": ) -> "Element":
"""Create the component. """Create the component.

View File

@ -7,6 +7,7 @@ from reflex.utils import lazy_loader
_MAPPING = { _MAPPING = {
"forms": [ "forms": [
"button", "button",
"datalist",
"fieldset", "fieldset",
"form", "form",
"input", "input",

View File

@ -4,6 +4,7 @@
# ------------------------------------------------------ # ------------------------------------------------------
from .forms import Button as Button from .forms import Button as Button
from .forms import Datalist as Datalist
from .forms import Fieldset as Fieldset from .forms import Fieldset as Fieldset
from .forms import Form as Form from .forms import Form as Form
from .forms import Input as Input from .forms import Input as Input
@ -17,6 +18,7 @@ from .forms import Progress as Progress
from .forms import Select as Select from .forms import Select as Select
from .forms import Textarea as Textarea from .forms import Textarea as Textarea
from .forms import button as button from .forms import button as button
from .forms import datalist as datalist
from .forms import fieldset as fieldset from .forms import fieldset as fieldset
from .forms import form as form from .forms import form as form
from .forms import input as input from .forms import input as input
@ -226,6 +228,7 @@ from .typography import ul as ul
_MAPPING = { _MAPPING = {
"forms": [ "forms": [
"button", "button",
"datalist",
"fieldset", "fieldset",
"form", "form",
"input", "input",

View File

@ -1,4 +1,4 @@
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" """Base classes."""
from typing import Union from typing import Union
@ -9,7 +9,7 @@ from reflex.vars.base import Var
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[Union[str, int, bool]]
# 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.

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, Callable, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.el.element import Element from reflex.components.el.element import Element
from reflex.event import EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -45,49 +45,29 @@ class BaseHTML(Element):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "BaseHTML": ) -> "BaseHTML":
"""Create the component. """Create the component.
Args: Args:
*children: The children of the component. *children: The children of the component.
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.

View File

@ -1,17 +1,24 @@
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" """Forms classes."""
from __future__ import annotations from __future__ import annotations
from hashlib import md5 from hashlib import md5
from typing import Any, Dict, Iterator, Set, Union from typing import Any, Dict, Iterator, Set, Tuple, Union
from jinja2 import Environment from jinja2 import Environment
from reflex.components.el.element import Element from reflex.components.el.element import Element
from reflex.components.tags.tag import Tag from reflex.components.tags.tag import Tag
from reflex.constants import Dirs, EventTriggers from reflex.constants import Dirs, EventTriggers
from reflex.event import EventChain, EventHandler, prevent_default from reflex.event import (
EventChain,
EventHandler,
input_event,
key_event,
prevent_default,
)
from reflex.utils.imports import ImportDict from reflex.utils.imports import ImportDict
from reflex.utils.types import is_optional
from reflex.vars import VarData from reflex.vars import VarData
from reflex.vars.base import LiteralVar, Var from reflex.vars.base import LiteralVar, Var
@ -78,7 +85,6 @@ class Datalist(BaseHTML):
"""Display the datalist element.""" """Display the datalist element."""
tag = "datalist" tag = "datalist"
# No unique attributes, only common ones are inherited
class Fieldset(Element): class Fieldset(Element):
@ -96,6 +102,24 @@ class Fieldset(Element):
name: Var[Union[str, int, bool]] name: Var[Union[str, int, bool]]
def on_submit_event_spec() -> Tuple[Var[Dict[str, Any]]]:
"""Event handler spec for the on_submit event.
Returns:
The event handler spec.
"""
return (FORM_DATA,)
def on_submit_string_event_spec() -> Tuple[Var[Dict[str, str]]]:
"""Event handler spec for the on_submit event.
Returns:
The event handler spec.
"""
return (FORM_DATA,)
class Form(BaseHTML): class Form(BaseHTML):
"""Display the form element.""" """Display the form element."""
@ -135,7 +159,7 @@ class Form(BaseHTML):
handle_submit_unique_name: Var[str] handle_submit_unique_name: Var[str]
# Fired when the form is submitted # Fired when the form is submitted
on_submit: EventHandler[lambda e0: [FORM_DATA]] on_submit: EventHandler[on_submit_event_spec, on_submit_string_event_spec]
@classmethod @classmethod
def create(cls, *children, **props): def create(cls, *children, **props):
@ -172,7 +196,7 @@ class Form(BaseHTML):
""" """
return { return {
"react": "useCallback", "react": "useCallback",
f"/{Dirs.STATE_PATH}": ["getRefValue", "getRefValues"], f"$/{Dirs.STATE_PATH}": ["getRefValue", "getRefValues"],
} }
def add_hooks(self) -> list[str]: def add_hooks(self) -> list[str]:
@ -215,18 +239,17 @@ class Form(BaseHTML):
# when ref start with refs_ it's an array of refs, so we need different method # when ref start with refs_ it's an array of refs, so we need different method
# to collect data # to collect data
if ref.startswith("refs_"): if ref.startswith("refs_"):
ref_var = Var(_js_expr=ref[:-3]).as_ref() ref_var = Var(_js_expr=ref[:-3])._as_ref()
form_refs[ref[len("refs_") : -3]] = Var( form_refs[ref[len("refs_") : -3]] = Var(
_js_expr=f"getRefValues({str(ref_var)})", _js_expr=f"getRefValues({ref_var!s})",
_var_data=VarData.merge(ref_var._get_all_var_data()), _var_data=VarData.merge(ref_var._get_all_var_data()),
) )
else: else:
ref_var = Var(_js_expr=ref).as_ref() ref_var = Var(_js_expr=ref)._as_ref()
form_refs[ref[4:]] = Var( form_refs[ref[4:]] = Var(
_js_expr=f"getRefValue({str(ref_var)})", _js_expr=f"getRefValue({ref_var!s})",
_var_data=VarData.merge(ref_var._get_all_var_data()), _var_data=VarData.merge(ref_var._get_all_var_data()),
) )
# print(repr(form_refs))
return form_refs return form_refs
def _get_vars(self, include_children: bool = True) -> Iterator[Var]: def _get_vars(self, include_children: bool = True) -> Iterator[Var]:
@ -234,7 +257,8 @@ class Form(BaseHTML):
yield from self._get_form_refs().values() yield from self._get_form_refs().values()
def _exclude_props(self) -> list[str]: def _exclude_props(self) -> list[str]:
return super()._exclude_props() + [ return [
*super()._exclude_props(),
"reset_on_submit", "reset_on_submit",
"handle_submit_unique_name", "handle_submit_unique_name",
] ]
@ -345,19 +369,46 @@ class Input(BaseHTML):
value: Var[Union[str, int, float]] value: Var[Union[str, int, float]]
# Fired when the input value changes # Fired when the input value changes
on_change: EventHandler[lambda e0: [e0.target.value]] on_change: EventHandler[input_event]
# Fired when the input gains focus # Fired when the input gains focus
on_focus: EventHandler[lambda e0: [e0.target.value]] on_focus: EventHandler[input_event]
# Fired when the input loses focus # Fired when the input loses focus
on_blur: EventHandler[lambda e0: [e0.target.value]] on_blur: EventHandler[input_event]
# Fired when a key is pressed down # Fired when a key is pressed down
on_key_down: EventHandler[lambda e0: [e0.key]] on_key_down: EventHandler[key_event]
# Fired when a key is released # Fired when a key is released
on_key_up: EventHandler[lambda e0: [e0.key]] on_key_up: EventHandler[key_event]
@classmethod
def create(cls, *children, **props):
"""Create an Input component.
Args:
*children: The children of the component.
**props: The properties of the component.
Returns:
The component.
"""
from reflex.vars.number import ternary_operation
value = props.get("value")
# React expects an empty string(instead of null) for controlled inputs.
if value is not None and is_optional(
(value_var := Var.create(value))._var_type
):
props["value"] = ternary_operation(
(value_var != Var.create(None)) # pyright: ignore [reportGeneralTypeIssues]
& (value_var != Var(_js_expr="undefined")),
value,
Var.create(""),
)
return super().create(*children, **props)
class Label(BaseHTML): class Label(BaseHTML):
@ -376,7 +427,6 @@ class Legend(BaseHTML):
"""Display the legend element.""" """Display the legend element."""
tag = "legend" tag = "legend"
# No unique attributes, only common ones are inherited
class Meter(BaseHTML): class Meter(BaseHTML):
@ -496,7 +546,7 @@ class Select(BaseHTML):
size: Var[Union[str, int, bool]] size: Var[Union[str, int, bool]]
# Fired when the select value changes # Fired when the select value changes
on_change: EventHandler[lambda e0: [e0.target.value]] on_change: EventHandler[input_event]
AUTO_HEIGHT_JS = """ AUTO_HEIGHT_JS = """
@ -546,6 +596,9 @@ class Textarea(BaseHTML):
# 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[Union[str, int, bool]]
# The default value of the textarea when initially rendered
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[Union[str, int, bool]]
@ -586,22 +639,59 @@ class Textarea(BaseHTML):
wrap: Var[Union[str, int, bool]] wrap: Var[Union[str, int, bool]]
# Fired when the input value changes # Fired when the input value changes
on_change: EventHandler[lambda e0: [e0.target.value]] on_change: EventHandler[input_event]
# Fired when the input gains focus # Fired when the input gains focus
on_focus: EventHandler[lambda e0: [e0.target.value]] on_focus: EventHandler[input_event]
# Fired when the input loses focus # Fired when the input loses focus
on_blur: EventHandler[lambda e0: [e0.target.value]] on_blur: EventHandler[input_event]
# Fired when a key is pressed down # Fired when a key is pressed down
on_key_down: EventHandler[lambda e0: [e0.key]] on_key_down: EventHandler[key_event]
# Fired when a key is released # Fired when a key is released
on_key_up: EventHandler[lambda e0: [e0.key]] on_key_up: EventHandler[key_event]
@classmethod
def create(cls, *children, **props):
"""Create a textarea component.
Args:
*children: The children of the textarea.
**props: The properties of the textarea.
Returns:
The textarea component.
Raises:
ValueError: when `enter_key_submit` is combined with `on_key_down`.
"""
enter_key_submit = props.get("enter_key_submit")
auto_height = props.get("auto_height")
custom_attrs = props.setdefault("custom_attrs", {})
if enter_key_submit is not None:
enter_key_submit = Var.create(enter_key_submit)
if "on_key_down" in props:
raise ValueError(
"Cannot combine `enter_key_submit` with `on_key_down`.",
)
custom_attrs["on_key_down"] = Var(
_js_expr=f"(e) => enterKeySubmitOnKeyDown(e, {enter_key_submit!s})",
_var_data=VarData.merge(enter_key_submit._get_all_var_data()),
)
if auto_height is not None:
auto_height = Var.create(auto_height)
custom_attrs["on_input"] = Var(
_js_expr=f"(e) => autoHeightOnInput(e, {auto_height!s})",
_var_data=VarData.merge(auto_height._get_all_var_data()),
)
return super().create(*children, **props)
def _exclude_props(self) -> list[str]: def _exclude_props(self) -> list[str]:
return super()._exclude_props() + [ return [
*super()._exclude_props(),
"auto_height", "auto_height",
"enter_key_submit", "enter_key_submit",
] ]
@ -619,30 +709,9 @@ class Textarea(BaseHTML):
custom_code.add(ENTER_KEY_SUBMIT_JS) custom_code.add(ENTER_KEY_SUBMIT_JS)
return custom_code return custom_code
def _render(self) -> Tag:
tag = super()._render()
if self.enter_key_submit is not None:
if "on_key_down" in self.event_triggers:
raise ValueError(
"Cannot combine `enter_key_submit` with `on_key_down`.",
)
tag.add_props(
on_key_down=Var(
_js_expr=f"(e) => enterKeySubmitOnKeyDown(e, {str(self.enter_key_submit)})",
_var_data=VarData.merge(self.enter_key_submit._get_all_var_data()),
)
)
if self.auto_height is not None:
tag.add_props(
on_input=Var(
_js_expr=f"(e) => autoHeightOnInput(e, {str(self.auto_height)})",
_var_data=VarData.merge(self.auto_height._get_all_var_data()),
)
)
return tag
button = Button.create button = Button.create
datalist = Datalist.create
fieldset = Fieldset.create fieldset = Fieldset.create
form = Form.create form = Form.create
input = Input.create input = Input.create

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" """Inline classes."""
from typing import Union from typing import Union

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" """Media classes."""
from typing import Any, Union from typing import Any, Union
@ -129,7 +129,6 @@ class Img(BaseHTML):
Returns: Returns:
The component. The component.
""" """
return ( return (
super().create(src=children[0], **props) super().create(src=children[0], **props)
@ -274,14 +273,12 @@ class Picture(BaseHTML):
"""Display the picture element.""" """Display the picture element."""
tag = "picture" tag = "picture"
# No unique attributes, only common ones are inherited
class Portal(BaseHTML): class Portal(BaseHTML):
"""Display the portal element.""" """Display the portal element."""
tag = "portal" tag = "portal"
# No unique attributes, only common ones are inherited
class Source(BaseHTML): class Source(BaseHTML):
@ -317,6 +314,42 @@ class Svg(BaseHTML):
xmlns: Var[str] xmlns: Var[str]
class Text(BaseHTML):
"""The SVG text component."""
tag = "text"
# The x coordinate of the starting point of the text baseline.
x: Var[Union[str, int]]
# The y coordinate of the starting point of the text baseline.
y: Var[Union[str, int]]
# Shifts the text position horizontally from a previous text element.
dx: Var[Union[str, int]]
# Shifts the text position vertically from a previous text element.
dy: Var[Union[str, int]]
# Rotates orientation of each individual glyph.
rotate: Var[Union[str, int]]
# How the text is stretched or compressed to fit the width defined by the text_length attribute.
length_adjust: Var[str]
# A width that the text should be scaled to fit.
text_length: Var[Union[str, int]]
class Line(BaseHTML):
"""The SVG line component."""
tag = "line"
# The x-axis coordinate of the line starting point.
x1: Var[Union[str, int]]
# The x-axis coordinate of the the line ending point.
x2: Var[Union[str, int]]
# The y-axis coordinate of the line starting point.
y1: Var[Union[str, int]]
# The y-axis coordinate of the the line ending point.
y2: Var[Union[str, int]]
# The total path length, in user units.
path_length: Var[int]
class Circle(BaseHTML): class Circle(BaseHTML):
"""The SVG circle component.""" """The SVG circle component."""
@ -331,6 +364,22 @@ class Circle(BaseHTML):
path_length: Var[int] path_length: Var[int]
class Ellipse(BaseHTML):
"""The SVG ellipse component."""
tag = "ellipse"
# The x position of the center of the ellipse.
cx: Var[Union[str, int]]
# The y position of the center of the ellipse.
cy: Var[Union[str, int]]
# The radius of the ellipse on the x axis.
rx: Var[Union[str, int]]
# The radius of the ellipse on the y axis.
ry: Var[Union[str, int]]
# The total length for the ellipse's circumference, in user units.
path_length: Var[int]
class Rect(BaseHTML): class Rect(BaseHTML):
"""The SVG rect component.""" """The SVG rect component."""
@ -394,6 +443,39 @@ class LinearGradient(BaseHTML):
y2: Var[Union[str, int, bool]] y2: Var[Union[str, int, bool]]
class RadialGradient(BaseHTML):
"""Display the radialGradient element."""
tag = "radialGradient"
# The x coordinate of the end circle of the radial gradient.
cx: Var[Union[str, int, bool]]
# The y coordinate of the end circle of the radial gradient.
cy: Var[Union[str, int, bool]]
# The radius of the start circle of the radial gradient.
fr: Var[Union[str, int, bool]]
# The x coordinate of the start circle of the radial gradient.
fx: Var[Union[str, int, bool]]
# The y coordinate of the start circle of the radial gradient.
fy: Var[Union[str, int, bool]]
# Units for the gradient.
gradient_units: Var[Union[str, bool]]
# Transform applied to the gradient.
gradient_transform: Var[Union[str, bool]]
# The radius of the end circle of the radial gradient.
r: Var[Union[str, int, bool]]
# Method used to spread the gradient.
spread_method: Var[Union[str, bool]]
class Stop(BaseHTML): class Stop(BaseHTML):
"""Display the stop element.""" """Display the stop element."""
@ -421,12 +503,16 @@ class Path(BaseHTML):
class SVG(ComponentNamespace): class SVG(ComponentNamespace):
"""SVG component namespace.""" """SVG component namespace."""
text = staticmethod(Text.create)
line = staticmethod(Line.create)
circle = staticmethod(Circle.create) circle = staticmethod(Circle.create)
ellipse = staticmethod(Ellipse.create)
rect = staticmethod(Rect.create) rect = staticmethod(Rect.create)
polygon = staticmethod(Polygon.create) polygon = staticmethod(Polygon.create)
path = staticmethod(Path.create) path = staticmethod(Path.create)
stop = staticmethod(Stop.create) stop = staticmethod(Stop.create)
linear_gradient = staticmethod(LinearGradient.create) linear_gradient = staticmethod(LinearGradient.create)
radial_gradient = staticmethod(RadialGradient.create)
defs = staticmethod(Defs.create) defs = staticmethod(Defs.create)
__call__ = staticmethod(Svg.create) __call__ = staticmethod(Svg.create)

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" """Metadata classes."""
from typing import List, Union from typing import List, Union
@ -8,7 +8,7 @@ from reflex.vars.base import Var
from .base import BaseHTML from .base import BaseHTML
class Base(BaseHTML): # noqa: E742 class Base(BaseHTML):
"""Display the base element.""" """Display the base element."""
tag = "base" tag = "base"
@ -18,13 +18,13 @@ class Base(BaseHTML): # noqa: E742
target: Var[Union[str, int, bool]] target: Var[Union[str, int, bool]]
class Head(BaseHTML): # noqa: E742 class Head(BaseHTML):
"""Display the head element.""" """Display the head element."""
tag = "head" tag = "head"
class Link(BaseHTML): # noqa: E742 class Link(BaseHTML):
"""Display the link element.""" """Display the link element."""
tag = "link" tag = "link"
@ -75,14 +75,14 @@ class Meta(BaseHTML): # Inherits common attributes from BaseHTML
name: Var[Union[str, int, bool]] name: Var[Union[str, int, bool]]
class Title(Element): # noqa: E742 class Title(Element):
"""Display the title element.""" """Display the title element."""
tag = "title" tag = "title"
# Had to be named with an underscore so it doesnt conflict with reflex.style Style in pyi # Had to be named with an underscore so it doesnt conflict with reflex.style Style in pyi
class StyleEl(Element): # noqa: E742 class StyleEl(Element):
"""Display the style element.""" """Display the style element."""
tag = "style" tag = "style"

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, Callable, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.components.el.element import Element from reflex.components.el.element import Element
from reflex.event import EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -49,49 +49,29 @@ class Base(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Base": ) -> "Base":
"""Create the component. """Create the component.
Args: Args:
*children: The children of the component. *children: The children of the component.
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -155,49 +135,29 @@ class Head(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Head": ) -> "Head":
"""Create the component. """Create the component.
Args: Args:
*children: The children of the component. *children: The children of the component.
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -274,42 +234,22 @@ class Link(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Link": ) -> "Link":
"""Create the component. """Create the component.
@ -325,7 +265,7 @@ class Link(BaseHTML):
rel: Specifies the relationship between the current document and the linked one rel: Specifies the relationship between the current document and the linked one
sizes: Specifies the sizes of icons for visual media sizes: Specifies the sizes of icons for visual media
type: Specifies the MIME type of the linked document type: Specifies the MIME type of the linked document
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -393,42 +333,22 @@ class Meta(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Meta": ) -> "Meta":
"""Create the component. """Create the component.
@ -439,7 +359,7 @@ class Meta(BaseHTML):
content: Defines the content of the metadata content: Defines the content of the metadata
http_equiv: Provides an HTTP header for the information/value of the content attribute http_equiv: Provides an HTTP header for the information/value of the content attribute
name: Specifies a name for the metadata name: Specifies a name for the metadata
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -479,42 +399,22 @@ class Title(Element):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Title": ) -> "Title":
"""Create the component. """Create the component.
@ -546,42 +446,22 @@ class StyleEl(Element):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "StyleEl": ) -> "StyleEl":
"""Create the component. """Create the component.

View File

@ -1,4 +1,4 @@
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" """Other classes."""
from typing import Union from typing import Union
@ -26,31 +26,39 @@ class Dialog(BaseHTML):
class Summary(BaseHTML): class Summary(BaseHTML):
"""Display the summary element.""" """Display the summary element.
Used as a summary or caption for a <details> element.
"""
tag = "summary" tag = "summary"
# No unique attributes, only common ones are inherited; used as a summary or caption for a <details> element
class Slot(BaseHTML): class Slot(BaseHTML):
"""Display the slot element.""" """Display the slot element.
Used as a placeholder inside a web component.
"""
tag = "slot" tag = "slot"
# No unique attributes, only common ones are inherited; used as a placeholder inside a web component
class Template(BaseHTML): class Template(BaseHTML):
"""Display the template element.""" """Display the template element.
Used for declaring fragments of HTML that can be cloned and inserted in the document.
"""
tag = "template" tag = "template"
# No unique attributes, only common ones are inherited; used for declaring fragments of HTML that can be cloned and inserted in the document
class Math(BaseHTML): class Math(BaseHTML):
"""Display the math element.""" """Display the math element.
Represents a mathematical expression.
"""
tag = "math" tag = "math"
# No unique attributes, only common ones are inherited; used for displaying mathematical expressions
class Html(BaseHTML): class Html(BaseHTML):

View File

@ -3,9 +3,9 @@
# ------------------- 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, Callable, Dict, Optional, Union, overload from typing import Any, Dict, Optional, Union, overload
from reflex.event import EventHandler, EventSpec from reflex.event import BASE_STATE, EventType
from reflex.style import Style from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
@ -47,42 +47,22 @@ class Details(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Details": ) -> "Details":
"""Create the component. """Create the component.
@ -90,7 +70,7 @@ class Details(BaseHTML):
Args: Args:
*children: The children of the component. *children: The children of the component.
open: Indicates whether the details will be visible (expanded) to the user open: Indicates whether the details will be visible (expanded) to the user
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -155,42 +135,22 @@ class Dialog(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Dialog": ) -> "Dialog":
"""Create the component. """Create the component.
@ -198,7 +158,7 @@ class Dialog(BaseHTML):
Args: Args:
*children: The children of the component. *children: The children of the component.
open: Indicates whether the dialog is active and can be interacted with open: Indicates whether the dialog is active and can be interacted with
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -262,49 +222,29 @@ class Summary(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Summary": ) -> "Summary":
"""Create the component. """Create the component.
Args: Args:
*children: The children of the component. *children: The children of the component.
access_key: No unique attributes, only common ones are inherited; used as a summary or caption for a <details> element Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -368,49 +308,29 @@ class Slot(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Slot": ) -> "Slot":
"""Create the component. """Create the component.
Args: Args:
*children: The children of the component. *children: The children of the component.
access_key: No unique attributes, only common ones are inherited; used as a placeholder inside a web component Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -474,49 +394,29 @@ class Template(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Template": ) -> "Template":
"""Create the component. """Create the component.
Args: Args:
*children: The children of the component. *children: The children of the component.
access_key: No unique attributes, only common ones are inherited; used for declaring fragments of HTML that can be cloned and inserted in the document Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -580,49 +480,29 @@ class Math(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Math": ) -> "Math":
"""Create the component. """Create the component.
Args: Args:
*children: The children of the component. *children: The children of the component.
access_key: No unique attributes, only common ones are inherited; used for displaying mathematical expressions Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
@ -687,42 +567,22 @@ class Html(BaseHTML):
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, str]]] = None, custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_double_click: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[ on_mount: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None, on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
] = None, on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
Union[EventHandler, EventSpec, list, Callable, Var] on_unmount: Optional[EventType[[], BASE_STATE]] = None,
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props, **props,
) -> "Html": ) -> "Html":
"""Create the component. """Create the component.
@ -730,7 +590,7 @@ class Html(BaseHTML):
Args: Args:
*children: The children of the component. *children: The children of the component.
manifest: Specifies the URL of the document's cache manifest (obsolete in HTML5) manifest: Specifies the URL of the document's cache manifest (obsolete in HTML5)
access_key: Provides a hint for generating a keyboard shortcut for the current element. 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. 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. 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. context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.

View File

@ -1,4 +1,4 @@
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" """Scripts classes."""
from typing import Union from typing import Union
@ -17,7 +17,6 @@ class Noscript(BaseHTML):
"""Display the noscript element.""" """Display the noscript element."""
tag = "noscript" tag = "noscript"
# No unique attributes, only common ones are inherited
class Script(BaseHTML): class Script(BaseHTML):

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